Jack2
1.9.7
|
00001 // u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */ 00002 /* 00003 JACK control API implementation 00004 00005 Copyright (C) 2008 Nedko Arnaudov 00006 Copyright (C) 2008 Grame 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; version 2 of the License. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 00021 */ 00022 00023 #ifndef WIN32 00024 #include <stdint.h> 00025 #include <dirent.h> 00026 #include <pthread.h> 00027 #endif 00028 00029 #include "types.h" 00030 #include <string.h> 00031 #include <errno.h> 00032 #include <stdio.h> 00033 #include <assert.h> 00034 #include <signal.h> 00035 #include <sys/utsname.h> 00036 00037 #include "jslist.h" 00038 #include "driver_interface.h" 00039 #include "JackError.h" 00040 #include "JackServer.h" 00041 #include "shm.h" 00042 #include "JackTools.h" 00043 #include "JackControlAPI.h" 00044 #include "JackLockedEngine.h" 00045 #include "JackConstants.h" 00046 #include "JackDriverLoader.h" 00047 #include "JackServerGlobals.h" 00048 00049 using namespace Jack; 00050 00051 struct jackctl_server 00052 { 00053 JSList * drivers; 00054 JSList * internals; 00055 JSList * parameters; 00056 00057 class JackServer * engine; 00058 00059 /* string, server name */ 00060 union jackctl_parameter_value name; 00061 union jackctl_parameter_value default_name; 00062 00063 /* bool, whether to be "realtime" */ 00064 union jackctl_parameter_value realtime; 00065 union jackctl_parameter_value default_realtime; 00066 00067 /* int32_t */ 00068 union jackctl_parameter_value realtime_priority; 00069 union jackctl_parameter_value default_realtime_priority; 00070 00071 /* bool, whether to exit once all clients have closed their connections */ 00072 union jackctl_parameter_value temporary; 00073 union jackctl_parameter_value default_temporary; 00074 00075 /* bool, whether to be verbose */ 00076 union jackctl_parameter_value verbose; 00077 union jackctl_parameter_value default_verbose; 00078 00079 /* int32_t, msecs; if zero, use period size. */ 00080 union jackctl_parameter_value client_timeout; 00081 union jackctl_parameter_value default_client_timeout; 00082 00083 /* uint32_t, clock source type */ 00084 union jackctl_parameter_value clock_source; 00085 union jackctl_parameter_value default_clock_source; 00086 00087 /* uint32_t, max port number */ 00088 union jackctl_parameter_value port_max; 00089 union jackctl_parameter_value default_port_max; 00090 00091 /* bool */ 00092 union jackctl_parameter_value replace_registry; 00093 union jackctl_parameter_value default_replace_registry; 00094 00095 /* bool, synchronous or asynchronous engine mode */ 00096 union jackctl_parameter_value sync; 00097 union jackctl_parameter_value default_sync; 00098 }; 00099 00100 struct jackctl_driver 00101 { 00102 jack_driver_desc_t * desc_ptr; 00103 JSList * parameters; 00104 JSList * set_parameters; 00105 JackDriverInfo* info; 00106 }; 00107 00108 struct jackctl_internal 00109 { 00110 jack_driver_desc_t * desc_ptr; 00111 JSList * parameters; 00112 JSList * set_parameters; 00113 int refnum; 00114 }; 00115 00116 struct jackctl_parameter 00117 { 00118 const char * name; 00119 const char * short_description; 00120 const char * long_description; 00121 jackctl_param_type_t type; 00122 bool is_set; 00123 union jackctl_parameter_value * value_ptr; 00124 union jackctl_parameter_value * default_value_ptr; 00125 00126 union jackctl_parameter_value value; 00127 union jackctl_parameter_value default_value; 00128 struct jackctl_driver * driver_ptr; 00129 char id; 00130 jack_driver_param_t * driver_parameter_ptr; 00131 jack_driver_param_constraint_desc_t * constraint_ptr; 00132 }; 00133 00134 static 00135 struct jackctl_parameter * 00136 jackctl_add_parameter( 00137 JSList ** parameters_list_ptr_ptr, 00138 const char * name, 00139 const char * short_description, 00140 const char * long_description, 00141 jackctl_param_type_t type, 00142 union jackctl_parameter_value * value_ptr, 00143 union jackctl_parameter_value * default_value_ptr, 00144 union jackctl_parameter_value value, 00145 jack_driver_param_constraint_desc_t * constraint_ptr = NULL) 00146 { 00147 struct jackctl_parameter * parameter_ptr; 00148 00149 parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter)); 00150 if (parameter_ptr == NULL) 00151 { 00152 jack_error("Cannot allocate memory for jackctl_parameter structure."); 00153 goto fail; 00154 } 00155 00156 parameter_ptr->name = name; 00157 parameter_ptr->short_description = short_description; 00158 parameter_ptr->long_description = long_description; 00159 parameter_ptr->type = type; 00160 parameter_ptr->is_set = false; 00161 00162 if (value_ptr == NULL) 00163 { 00164 value_ptr = ¶meter_ptr->value; 00165 } 00166 00167 if (default_value_ptr == NULL) 00168 { 00169 default_value_ptr = ¶meter_ptr->default_value; 00170 } 00171 00172 parameter_ptr->value_ptr = value_ptr; 00173 parameter_ptr->default_value_ptr = default_value_ptr; 00174 00175 *value_ptr = *default_value_ptr = value; 00176 00177 parameter_ptr->driver_ptr = NULL; 00178 parameter_ptr->driver_parameter_ptr = NULL; 00179 parameter_ptr->id = 0; 00180 parameter_ptr->constraint_ptr = constraint_ptr; 00181 00182 *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr); 00183 00184 return parameter_ptr; 00185 00186 fail: 00187 return NULL; 00188 } 00189 00190 static 00191 void 00192 jackctl_free_driver_parameters( 00193 struct jackctl_driver * driver_ptr) 00194 { 00195 JSList * next_node_ptr; 00196 00197 while (driver_ptr->parameters) 00198 { 00199 next_node_ptr = driver_ptr->parameters->next; 00200 free(driver_ptr->parameters->data); 00201 free(driver_ptr->parameters); 00202 driver_ptr->parameters = next_node_ptr; 00203 } 00204 00205 while (driver_ptr->set_parameters) 00206 { 00207 next_node_ptr = driver_ptr->set_parameters->next; 00208 free(driver_ptr->set_parameters->data); 00209 free(driver_ptr->set_parameters); 00210 driver_ptr->set_parameters = next_node_ptr; 00211 } 00212 } 00213 00214 static 00215 bool 00216 jackctl_add_driver_parameters( 00217 struct jackctl_driver * driver_ptr) 00218 { 00219 uint32_t i; 00220 union jackctl_parameter_value jackctl_value; 00221 jackctl_param_type_t jackctl_type; 00222 struct jackctl_parameter * parameter_ptr; 00223 jack_driver_param_desc_t * descriptor_ptr; 00224 00225 for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++) 00226 { 00227 descriptor_ptr = driver_ptr->desc_ptr->params + i; 00228 00229 switch (descriptor_ptr->type) 00230 { 00231 case JackDriverParamInt: 00232 jackctl_type = JackParamInt; 00233 jackctl_value.i = descriptor_ptr->value.i; 00234 break; 00235 case JackDriverParamUInt: 00236 jackctl_type = JackParamUInt; 00237 jackctl_value.ui = descriptor_ptr->value.ui; 00238 break; 00239 case JackDriverParamChar: 00240 jackctl_type = JackParamChar; 00241 jackctl_value.c = descriptor_ptr->value.c; 00242 break; 00243 case JackDriverParamString: 00244 jackctl_type = JackParamString; 00245 strcpy(jackctl_value.str, descriptor_ptr->value.str); 00246 break; 00247 case JackDriverParamBool: 00248 jackctl_type = JackParamBool; 00249 jackctl_value.b = descriptor_ptr->value.i; 00250 break; 00251 default: 00252 jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type); 00253 assert(0); 00254 goto fail; 00255 } 00256 00257 parameter_ptr = jackctl_add_parameter( 00258 &driver_ptr->parameters, 00259 descriptor_ptr->name, 00260 descriptor_ptr->short_desc, 00261 descriptor_ptr->long_desc, 00262 jackctl_type, 00263 NULL, 00264 NULL, 00265 jackctl_value, 00266 descriptor_ptr->constraint); 00267 00268 if (parameter_ptr == NULL) 00269 { 00270 goto fail; 00271 } 00272 00273 parameter_ptr->driver_ptr = driver_ptr; 00274 parameter_ptr->id = descriptor_ptr->character; 00275 } 00276 00277 return true; 00278 00279 fail: 00280 jackctl_free_driver_parameters(driver_ptr); 00281 00282 return false; 00283 } 00284 00285 static int 00286 jackctl_drivers_load( 00287 struct jackctl_server * server_ptr) 00288 { 00289 struct jackctl_driver * driver_ptr; 00290 JSList *node_ptr; 00291 JSList *descriptor_node_ptr; 00292 00293 descriptor_node_ptr = jack_drivers_load(NULL); 00294 if (descriptor_node_ptr == NULL) 00295 { 00296 jack_error("could not find any drivers in driver directory!"); 00297 return false; 00298 } 00299 00300 while (descriptor_node_ptr != NULL) 00301 { 00302 driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver)); 00303 if (driver_ptr == NULL) 00304 { 00305 jack_error("memory allocation of jackctl_driver structure failed."); 00306 goto next; 00307 } 00308 00309 driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; 00310 driver_ptr->parameters = NULL; 00311 driver_ptr->set_parameters = NULL; 00312 00313 if (!jackctl_add_driver_parameters(driver_ptr)) 00314 { 00315 assert(driver_ptr->parameters == NULL); 00316 free(driver_ptr); 00317 goto next; 00318 } 00319 00320 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr); 00321 00322 next: 00323 node_ptr = descriptor_node_ptr; 00324 descriptor_node_ptr = descriptor_node_ptr->next; 00325 free(node_ptr); 00326 } 00327 00328 return true; 00329 } 00330 00331 static 00332 void 00333 jackctl_server_free_drivers( 00334 struct jackctl_server * server_ptr) 00335 { 00336 JSList * next_node_ptr; 00337 struct jackctl_driver * driver_ptr; 00338 00339 while (server_ptr->drivers) 00340 { 00341 next_node_ptr = server_ptr->drivers->next; 00342 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data; 00343 00344 jackctl_free_driver_parameters(driver_ptr); 00345 free(driver_ptr->desc_ptr->params); 00346 free(driver_ptr->desc_ptr); 00347 free(driver_ptr); 00348 00349 free(server_ptr->drivers); 00350 server_ptr->drivers = next_node_ptr; 00351 } 00352 } 00353 00354 static int 00355 jackctl_internals_load( 00356 struct jackctl_server * server_ptr) 00357 { 00358 struct jackctl_internal * internal_ptr; 00359 JSList *node_ptr; 00360 JSList *descriptor_node_ptr; 00361 00362 descriptor_node_ptr = jack_internals_load(NULL); 00363 if (descriptor_node_ptr == NULL) 00364 { 00365 jack_error("could not find any internals in driver directory!"); 00366 return false; 00367 } 00368 00369 while (descriptor_node_ptr != NULL) 00370 { 00371 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal)); 00372 if (internal_ptr == NULL) 00373 { 00374 jack_error("memory allocation of jackctl_driver structure failed."); 00375 goto next; 00376 } 00377 00378 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; 00379 internal_ptr->parameters = NULL; 00380 internal_ptr->set_parameters = NULL; 00381 00382 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr)) 00383 { 00384 assert(internal_ptr->parameters == NULL); 00385 free(internal_ptr); 00386 goto next; 00387 } 00388 00389 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr); 00390 00391 next: 00392 node_ptr = descriptor_node_ptr; 00393 descriptor_node_ptr = descriptor_node_ptr->next; 00394 free(node_ptr); 00395 } 00396 00397 return true; 00398 } 00399 00400 static 00401 void 00402 jackctl_server_free_internals( 00403 struct jackctl_server * server_ptr) 00404 { 00405 JSList * next_node_ptr; 00406 struct jackctl_internal * internal_ptr; 00407 00408 while (server_ptr->internals) 00409 { 00410 next_node_ptr = server_ptr->internals->next; 00411 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data; 00412 00413 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr); 00414 free(internal_ptr->desc_ptr->params); 00415 free(internal_ptr->desc_ptr); 00416 free(internal_ptr); 00417 00418 free(server_ptr->internals); 00419 server_ptr->internals = next_node_ptr; 00420 } 00421 } 00422 00423 static 00424 void 00425 jackctl_server_free_parameters( 00426 struct jackctl_server * server_ptr) 00427 { 00428 JSList * next_node_ptr; 00429 00430 while (server_ptr->parameters) 00431 { 00432 next_node_ptr = server_ptr->parameters->next; 00433 free(server_ptr->parameters->data); 00434 free(server_ptr->parameters); 00435 server_ptr->parameters = next_node_ptr; 00436 } 00437 } 00438 00439 #ifdef WIN32 00440 00441 static HANDLE waitEvent; 00442 00443 static void do_nothing_handler(int signum) 00444 { 00445 printf("jack main caught signal %d\n", signum); 00446 (void) signal(SIGINT, SIG_DFL); 00447 SetEvent(waitEvent); 00448 } 00449 00450 sigset_t 00451 jackctl_setup_signals( 00452 unsigned int flags) 00453 { 00454 if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { 00455 jack_error("CreateEvent fails err = %ld", GetLastError()); 00456 return 0; 00457 } 00458 00459 (void) signal(SIGINT, do_nothing_handler); 00460 (void) signal(SIGABRT, do_nothing_handler); 00461 (void) signal(SIGTERM, do_nothing_handler); 00462 00463 return (sigset_t)waitEvent; 00464 } 00465 00466 void jackctl_wait_signals(sigset_t signals) 00467 { 00468 if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { 00469 jack_error("WaitForSingleObject fails err = %ld", GetLastError()); 00470 } 00471 } 00472 00473 #else 00474 00475 static 00476 void 00477 do_nothing_handler(int sig) 00478 { 00479 /* this is used by the child (active) process, but it never 00480 gets called unless we are already shutting down after 00481 another signal. 00482 */ 00483 char buf[64]; 00484 snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig); 00485 } 00486 00487 EXPORT sigset_t 00488 jackctl_setup_signals( 00489 unsigned int flags) 00490 { 00491 sigset_t signals; 00492 sigset_t allsignals; 00493 struct sigaction action; 00494 int i; 00495 00496 /* ensure that we are in our own process group so that 00497 kill (SIG, -pgrp) does the right thing. 00498 */ 00499 00500 setsid(); 00501 00502 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 00503 00504 /* what's this for? 00505 00506 POSIX says that signals are delivered like this: 00507 00508 * if a thread has blocked that signal, it is not 00509 a candidate to receive the signal. 00510 * of all threads not blocking the signal, pick 00511 one at random, and deliver the signal. 00512 00513 this means that a simple-minded multi-threaded program can 00514 expect to get POSIX signals delivered randomly to any one 00515 of its threads, 00516 00517 here, we block all signals that we think we might receive 00518 and want to catch. all "child" threads will inherit this 00519 setting. if we create a thread that calls sigwait() on the 00520 same set of signals, implicitly unblocking all those 00521 signals. any of those signals that are delivered to the 00522 process will be delivered to that thread, and that thread 00523 alone. this makes cleanup for a signal-driven exit much 00524 easier, since we know which thread is doing it and more 00525 importantly, we are free to call async-unsafe functions, 00526 because the code is executing in normal thread context 00527 after a return from sigwait(). 00528 */ 00529 00530 sigemptyset(&signals); 00531 sigaddset(&signals, SIGHUP); 00532 sigaddset(&signals, SIGINT); 00533 sigaddset(&signals, SIGQUIT); 00534 sigaddset(&signals, SIGPIPE); 00535 sigaddset(&signals, SIGTERM); 00536 sigaddset(&signals, SIGUSR1); 00537 sigaddset(&signals, SIGUSR2); 00538 00539 /* all child threads will inherit this mask unless they 00540 * explicitly reset it 00541 */ 00542 00543 pthread_sigmask(SIG_BLOCK, &signals, 0); 00544 00545 /* install a do-nothing handler because otherwise pthreads 00546 behaviour is undefined when we enter sigwait. 00547 */ 00548 00549 sigfillset(&allsignals); 00550 action.sa_handler = do_nothing_handler; 00551 action.sa_mask = allsignals; 00552 action.sa_flags = SA_RESTART|SA_RESETHAND; 00553 00554 for (i = 1; i < NSIG; i++) 00555 { 00556 if (sigismember (&signals, i)) 00557 { 00558 sigaction(i, &action, 0); 00559 } 00560 } 00561 00562 return signals; 00563 } 00564 00565 EXPORT void 00566 jackctl_wait_signals(sigset_t signals) 00567 { 00568 int sig; 00569 bool waiting = true; 00570 00571 while (waiting) { 00572 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check 00573 sigwait(&signals); 00574 #else 00575 sigwait(&signals, &sig); 00576 #endif 00577 fprintf(stderr, "jack main caught signal %d\n", sig); 00578 00579 switch (sig) { 00580 case SIGUSR1: 00581 //jack_dump_configuration(engine, 1); 00582 break; 00583 case SIGUSR2: 00584 // driver exit 00585 waiting = false; 00586 break; 00587 case SIGTTOU: 00588 break; 00589 default: 00590 waiting = false; 00591 break; 00592 } 00593 } 00594 00595 if (sig != SIGSEGV) { 00596 // unblock signals so we can see them during shutdown. 00597 // this will help prod developers not to lose sight of 00598 // bugs that cause segfaults etc. during shutdown. 00599 sigprocmask(SIG_UNBLOCK, &signals, 0); 00600 } 00601 } 00602 #endif 00603 00604 static 00605 jack_driver_param_constraint_desc_t * 00606 get_realtime_priority_constraint() 00607 { 00608 jack_driver_param_constraint_desc_t * constraint_ptr; 00609 int min, max; 00610 00611 if (!jack_get_thread_realtime_priority_range(&min, &max)) 00612 { 00613 return NULL; 00614 } 00615 00616 //jack_info("realtime priority range is (%d,%d)", min, max); 00617 00618 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t)); 00619 if (constraint_ptr == NULL) 00620 { 00621 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure."); 00622 return NULL; 00623 } 00624 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE; 00625 00626 constraint_ptr->constraint.range.min.i = min; 00627 constraint_ptr->constraint.range.max.i = max; 00628 00629 return constraint_ptr; 00630 } 00631 00632 EXPORT jackctl_server_t * jackctl_server_create( 00633 bool (* on_device_acquire)(const char * device_name), 00634 void (* on_device_release)(const char * device_name)) 00635 { 00636 struct jackctl_server * server_ptr; 00637 union jackctl_parameter_value value; 00638 00639 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server)); 00640 if (server_ptr == NULL) 00641 { 00642 jack_error("Cannot allocate memory for jackctl_server structure."); 00643 goto fail; 00644 } 00645 00646 server_ptr->drivers = NULL; 00647 server_ptr->internals = NULL; 00648 server_ptr->parameters = NULL; 00649 server_ptr->engine = NULL; 00650 00651 strcpy(value.str, JACK_DEFAULT_SERVER_NAME); 00652 if (jackctl_add_parameter( 00653 &server_ptr->parameters, 00654 "name", 00655 "Server name to use.", 00656 "", 00657 JackParamString, 00658 &server_ptr->name, 00659 &server_ptr->default_name, 00660 value) == NULL) 00661 { 00662 goto fail_free_parameters; 00663 } 00664 00665 value.b = false; 00666 if (jackctl_add_parameter( 00667 &server_ptr->parameters, 00668 "realtime", 00669 "Whether to use realtime mode.", 00670 "Use realtime scheduling. This is needed for reliable low-latency performance. On most systems, it requires JACK to run with special scheduler and memory allocation privileges, which may be obtained in several ways. On Linux you should use PAM.", 00671 JackParamBool, 00672 &server_ptr->realtime, 00673 &server_ptr->default_realtime, 00674 value) == NULL) 00675 { 00676 goto fail_free_parameters; 00677 } 00678 00679 struct utsname utsname; 00680 int success; 00681 success = uname( &utsname ); 00682 if( success == 0 && strstr( utsname.version, "ccrma" ) ) 00683 value.i = 60; 00684 else 00685 value.i = 20; 00686 if (jackctl_add_parameter( 00687 &server_ptr->parameters, 00688 "realtime-priority", 00689 "Scheduler priority when running in realtime mode.", 00690 "", 00691 JackParamInt, 00692 &server_ptr->realtime_priority, 00693 &server_ptr->default_realtime_priority, 00694 value, 00695 get_realtime_priority_constraint()) == NULL) 00696 { 00697 goto fail_free_parameters; 00698 } 00699 00700 value.b = false; 00701 if (jackctl_add_parameter( 00702 &server_ptr->parameters, 00703 "temporary", 00704 "Exit once all clients have closed their connections.", 00705 "", 00706 JackParamBool, 00707 &server_ptr->temporary, 00708 &server_ptr->default_temporary, 00709 value) == NULL) 00710 { 00711 goto fail_free_parameters; 00712 } 00713 00714 value.b = false; 00715 if (jackctl_add_parameter( 00716 &server_ptr->parameters, 00717 "verbose", 00718 "Verbose mode.", 00719 "", 00720 JackParamBool, 00721 &server_ptr->verbose, 00722 &server_ptr->default_verbose, 00723 value) == NULL) 00724 { 00725 goto fail_free_parameters; 00726 } 00727 00728 value.i = 0; 00729 if (jackctl_add_parameter( 00730 &server_ptr->parameters, 00731 "client-timeout", 00732 "Client timeout limit in milliseconds.", 00733 "", 00734 JackParamInt, 00735 &server_ptr->client_timeout, 00736 &server_ptr->default_client_timeout, 00737 value) == NULL) 00738 { 00739 goto fail_free_parameters; 00740 } 00741 00742 value.ui = 0; 00743 if (jackctl_add_parameter( 00744 &server_ptr->parameters, 00745 "clock-source", 00746 "Clocksource type : c(ycle) | h(pet) | s(ystem).", 00747 "", 00748 JackParamUInt, 00749 &server_ptr->clock_source, 00750 &server_ptr->default_clock_source, 00751 value) == NULL) 00752 { 00753 goto fail_free_parameters; 00754 } 00755 00756 value.ui = PORT_NUM; 00757 if (jackctl_add_parameter( 00758 &server_ptr->parameters, 00759 "port-max", 00760 "Maximum number of ports.", 00761 "", 00762 JackParamUInt, 00763 &server_ptr->port_max, 00764 &server_ptr->default_port_max, 00765 value) == NULL) 00766 { 00767 goto fail_free_parameters; 00768 } 00769 00770 value.b = false; 00771 if (jackctl_add_parameter( 00772 &server_ptr->parameters, 00773 "replace-registry", 00774 "Replace shared memory registry.", 00775 "", 00776 JackParamBool, 00777 &server_ptr->replace_registry, 00778 &server_ptr->default_replace_registry, 00779 value) == NULL) 00780 { 00781 goto fail_free_parameters; 00782 } 00783 00784 value.b = false; 00785 if (jackctl_add_parameter( 00786 &server_ptr->parameters, 00787 "sync", 00788 "Use server synchronous mode.", 00789 "", 00790 JackParamBool, 00791 &server_ptr->sync, 00792 &server_ptr->default_sync, 00793 value) == NULL) 00794 { 00795 goto fail_free_parameters; 00796 } 00797 00798 JackServerGlobals::on_device_acquire = on_device_acquire; 00799 JackServerGlobals::on_device_release = on_device_release; 00800 00801 if (!jackctl_drivers_load(server_ptr)) 00802 { 00803 goto fail_free_parameters; 00804 } 00805 00806 /* Allowed to fail */ 00807 jackctl_internals_load(server_ptr); 00808 00809 return server_ptr; 00810 00811 fail_free_parameters: 00812 jackctl_server_free_parameters(server_ptr); 00813 00814 free(server_ptr); 00815 00816 fail: 00817 return NULL; 00818 } 00819 00820 EXPORT void jackctl_server_destroy(jackctl_server *server_ptr) 00821 { 00822 jackctl_server_free_drivers(server_ptr); 00823 jackctl_server_free_internals(server_ptr); 00824 jackctl_server_free_parameters(server_ptr); 00825 free(server_ptr); 00826 } 00827 00828 EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr) 00829 { 00830 return server_ptr->drivers; 00831 } 00832 00833 EXPORT bool jackctl_server_stop(jackctl_server *server_ptr) 00834 { 00835 server_ptr->engine->Stop(); 00836 return true; 00837 } 00838 00839 EXPORT bool jackctl_server_close(jackctl_server *server_ptr) 00840 { 00841 server_ptr->engine->Close(); 00842 delete server_ptr->engine; 00843 00844 /* clean up shared memory and files from this server instance */ 00845 jack_log("cleaning up shared memory"); 00846 00847 jack_cleanup_shm(); 00848 00849 jack_log("cleaning up files"); 00850 00851 JackTools::CleanupFiles(server_ptr->name.str); 00852 00853 jack_log("unregistering server `%s'", server_ptr->name.str); 00854 00855 jack_unregister_server(server_ptr->name.str); 00856 00857 server_ptr->engine = NULL; 00858 00859 return true; 00860 } 00861 00862 EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr) 00863 { 00864 return server_ptr->parameters; 00865 } 00866 00867 EXPORT bool 00868 jackctl_server_open( 00869 jackctl_server *server_ptr, 00870 jackctl_driver *driver_ptr) 00871 { 00872 int rc; 00873 00874 rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b); 00875 switch (rc) 00876 { 00877 case EEXIST: 00878 jack_error("`%s' server already active", server_ptr->name.str); 00879 goto fail; 00880 case ENOSPC: 00881 jack_error("too many servers already active"); 00882 goto fail; 00883 case ENOMEM: 00884 jack_error("no access to shm registry"); 00885 goto fail; 00886 } 00887 00888 jack_log("server `%s' registered", server_ptr->name.str); 00889 00890 /* clean up shared memory and files from any previous 00891 * instance of this server name */ 00892 jack_cleanup_shm(); 00893 JackTools::CleanupFiles(server_ptr->name.str); 00894 00895 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) 00896 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ 00897 00898 /* check port max value before allocating server */ 00899 if (server_ptr->port_max.ui > PORT_NUM_MAX) { 00900 jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); 00901 goto fail; 00902 } 00903 00904 /* get the engine/driver started */ 00905 server_ptr->engine = new JackServer( 00906 server_ptr->sync.b, 00907 server_ptr->temporary.b, 00908 server_ptr->client_timeout.i, 00909 server_ptr->realtime.b, 00910 server_ptr->realtime_priority.i, 00911 server_ptr->port_max.ui, 00912 server_ptr->verbose.b, 00913 (jack_timer_type_t)server_ptr->clock_source.ui, 00914 server_ptr->name.str); 00915 if (server_ptr->engine == NULL) 00916 { 00917 jack_error("Failed to create new JackServer object"); 00918 goto fail_unregister; 00919 } 00920 00921 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters); 00922 if (rc < 0) 00923 { 00924 jack_error("JackServer::Open() failed with %d", rc); 00925 goto fail_delete; 00926 } 00927 00928 return true; 00929 00930 fail_delete: 00931 delete server_ptr->engine; 00932 server_ptr->engine = NULL; 00933 00934 fail_unregister: 00935 jack_log("cleaning up shared memory"); 00936 00937 jack_cleanup_shm(); 00938 00939 jack_log("cleaning up files"); 00940 00941 JackTools::CleanupFiles(server_ptr->name.str); 00942 00943 jack_log("unregistering server `%s'", server_ptr->name.str); 00944 00945 jack_unregister_server(server_ptr->name.str); 00946 00947 fail: 00948 return false; 00949 } 00950 00951 EXPORT bool 00952 jackctl_server_start( 00953 jackctl_server *server_ptr) 00954 { 00955 int rc = server_ptr->engine->Start(); 00956 bool result = rc >= 0; 00957 if (! result) 00958 { 00959 jack_error("JackServer::Start() failed with %d", rc); 00960 } 00961 return result; 00962 } 00963 00964 EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr) 00965 { 00966 return driver_ptr->desc_ptr->name; 00967 } 00968 00969 EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr) 00970 { 00971 return driver_ptr->parameters; 00972 } 00973 00974 EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr) 00975 { 00976 return driver_ptr->desc_ptr; 00977 } 00978 00979 EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr) 00980 { 00981 return parameter_ptr->name; 00982 } 00983 00984 EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr) 00985 { 00986 return parameter_ptr->short_description; 00987 } 00988 00989 EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr) 00990 { 00991 return parameter_ptr->long_description; 00992 } 00993 00994 EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr) 00995 { 00996 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0; 00997 } 00998 00999 EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr) 01000 { 01001 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0; 01002 } 01003 01004 EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr) 01005 { 01006 if (!jackctl_parameter_has_enum_constraint(parameter_ptr)) 01007 { 01008 return 0; 01009 } 01010 01011 return parameter_ptr->constraint_ptr->constraint.enumeration.count; 01012 } 01013 01014 EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index) 01015 { 01016 jack_driver_param_value_t * value_ptr; 01017 union jackctl_parameter_value jackctl_value; 01018 01019 value_ptr = ¶meter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value; 01020 01021 switch (parameter_ptr->type) 01022 { 01023 case JackParamInt: 01024 jackctl_value.i = value_ptr->i; 01025 break; 01026 case JackParamUInt: 01027 jackctl_value.ui = value_ptr->ui; 01028 break; 01029 case JackParamChar: 01030 jackctl_value.c = value_ptr->c; 01031 break; 01032 case JackParamString: 01033 strcpy(jackctl_value.str, value_ptr->str); 01034 break; 01035 default: 01036 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type); 01037 assert(0); 01038 } 01039 01040 return jackctl_value; 01041 } 01042 01043 EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index) 01044 { 01045 return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc; 01046 } 01047 01048 EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr) 01049 { 01050 switch (parameter_ptr->type) 01051 { 01052 case JackParamInt: 01053 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i; 01054 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i; 01055 return; 01056 case JackParamUInt: 01057 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui; 01058 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui; 01059 return; 01060 default: 01061 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type); 01062 assert(0); 01063 } 01064 } 01065 01066 EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr) 01067 { 01068 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0; 01069 } 01070 01071 EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr) 01072 { 01073 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0; 01074 } 01075 01076 EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr) 01077 { 01078 return parameter_ptr->type; 01079 } 01080 01081 EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr) 01082 { 01083 return parameter_ptr->id; 01084 } 01085 01086 EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr) 01087 { 01088 return parameter_ptr->is_set; 01089 } 01090 01091 EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr) 01092 { 01093 return *parameter_ptr->value_ptr; 01094 } 01095 01096 EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr) 01097 { 01098 if (!parameter_ptr->is_set) 01099 { 01100 return true; 01101 } 01102 01103 parameter_ptr->is_set = false; 01104 01105 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr; 01106 01107 return true; 01108 } 01109 01110 EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr) 01111 { 01112 bool new_driver_parameter; 01113 01114 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */ 01115 if (parameter_ptr->driver_ptr != NULL) 01116 { 01117 /* jack_info("setting driver parameter %p ...", parameter_ptr); */ 01118 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL; 01119 if (new_driver_parameter) 01120 { 01121 /* jack_info("new driver parameter..."); */ 01122 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t)); 01123 if (parameter_ptr->driver_parameter_ptr == NULL) 01124 { 01125 jack_error ("Allocation of jack_driver_param_t structure failed"); 01126 return false; 01127 } 01128 01129 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id; 01130 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); 01131 } 01132 01133 switch (parameter_ptr->type) 01134 { 01135 case JackParamInt: 01136 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i; 01137 break; 01138 case JackParamUInt: 01139 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui; 01140 break; 01141 case JackParamChar: 01142 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c; 01143 break; 01144 case JackParamString: 01145 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str); 01146 break; 01147 case JackParamBool: 01148 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b; 01149 break; 01150 default: 01151 jack_error("unknown parameter type %i", (int)parameter_ptr->type); 01152 assert(0); 01153 01154 if (new_driver_parameter) 01155 { 01156 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); 01157 } 01158 01159 return false; 01160 } 01161 } 01162 01163 parameter_ptr->is_set = true; 01164 *parameter_ptr->value_ptr = *value_ptr; 01165 01166 return true; 01167 } 01168 01169 EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr) 01170 { 01171 return *parameter_ptr->default_value_ptr; 01172 } 01173 01174 // Internals clients 01175 01176 EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr) 01177 { 01178 return server_ptr->internals; 01179 } 01180 01181 EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr) 01182 { 01183 return internal_ptr->desc_ptr->name; 01184 } 01185 01186 EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr) 01187 { 01188 return internal_ptr->parameters; 01189 } 01190 01191 EXPORT bool jackctl_server_load_internal( 01192 jackctl_server * server_ptr, 01193 jackctl_internal * internal) 01194 { 01195 int status; 01196 if (server_ptr->engine != NULL) { 01197 server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, -1, &status); 01198 return (internal->refnum > 0); 01199 } else { 01200 return false; 01201 } 01202 } 01203 01204 EXPORT bool jackctl_server_unload_internal( 01205 jackctl_server * server_ptr, 01206 jackctl_internal * internal) 01207 { 01208 int status; 01209 if (server_ptr->engine != NULL && internal->refnum > 0) { 01210 // Client object is internally kept in JackEngine, and will be desallocated in InternalClientUnload 01211 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0); 01212 } else { 01213 return false; 01214 } 01215 } 01216 01217 EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01218 { 01219 if (server_ptr->engine != NULL) { 01220 if (server_ptr->engine->IsRunning()) { 01221 jack_error("cannot add a slave in a running server"); 01222 return false; 01223 } else { 01224 driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); 01225 return (driver_ptr->info != 0); 01226 } 01227 } else { 01228 return false; 01229 } 01230 } 01231 01232 EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01233 { 01234 if (server_ptr->engine != NULL) { 01235 if (server_ptr->engine->IsRunning()) { 01236 jack_error("cannot remove a slave from a running server"); 01237 return false; 01238 } else { 01239 server_ptr->engine->RemoveSlave(driver_ptr->info); 01240 delete driver_ptr->info; 01241 return true; 01242 } 01243 } else { 01244 return false; 01245 } 01246 } 01247 01248 EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01249 { 01250 if (server_ptr->engine != NULL) { 01251 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0); 01252 } else { 01253 return false; 01254 } 01255 } 01256