Jack2 1.9.6
|
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, "PREEMPT RT" ) ) 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 server_ptr->engine->Close(); 00837 delete server_ptr->engine; 00838 00839 /* clean up shared memory and files from this server instance */ 00840 jack_log("cleaning up shared memory"); 00841 00842 jack_cleanup_shm(); 00843 00844 jack_log("cleaning up files"); 00845 00846 JackTools::CleanupFiles(server_ptr->name.str); 00847 00848 jack_log("unregistering server `%s'", server_ptr->name.str); 00849 00850 jack_unregister_server(server_ptr->name.str); 00851 00852 server_ptr->engine = NULL; 00853 00854 return true; 00855 } 00856 00857 EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr) 00858 { 00859 return server_ptr->parameters; 00860 } 00861 00862 EXPORT bool 00863 jackctl_server_start( 00864 jackctl_server *server_ptr, 00865 jackctl_driver *driver_ptr) 00866 { 00867 int rc; 00868 00869 rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b); 00870 switch (rc) 00871 { 00872 case EEXIST: 00873 jack_error("`%s' server already active", server_ptr->name.str); 00874 goto fail; 00875 case ENOSPC: 00876 jack_error("too many servers already active"); 00877 goto fail; 00878 case ENOMEM: 00879 jack_error("no access to shm registry"); 00880 goto fail; 00881 } 00882 00883 jack_log("server `%s' registered", server_ptr->name.str); 00884 00885 /* clean up shared memory and files from any previous 00886 * instance of this server name */ 00887 jack_cleanup_shm(); 00888 JackTools::CleanupFiles(server_ptr->name.str); 00889 00890 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) 00891 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ 00892 00893 /* check port max value before allocating server */ 00894 if (server_ptr->port_max.ui > PORT_NUM_MAX) { 00895 jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); 00896 goto fail; 00897 } 00898 00899 /* get the engine/driver started */ 00900 server_ptr->engine = new JackServer( 00901 server_ptr->sync.b, 00902 server_ptr->temporary.b, 00903 server_ptr->client_timeout.i, 00904 server_ptr->realtime.b, 00905 server_ptr->realtime_priority.i, 00906 server_ptr->port_max.ui, 00907 server_ptr->verbose.b, 00908 (jack_timer_type_t)server_ptr->clock_source.ui, 00909 server_ptr->name.str); 00910 if (server_ptr->engine == NULL) 00911 { 00912 jack_error("Failed to create new JackServer object"); 00913 goto fail_unregister; 00914 } 00915 00916 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters); 00917 if (rc < 0) 00918 { 00919 jack_error("JackServer::Open() failed with %d", rc); 00920 goto fail_delete; 00921 } 00922 00923 rc = server_ptr->engine->Start(); 00924 if (rc < 0) 00925 { 00926 jack_error("JackServer::Start() failed with %d", rc); 00927 goto fail_close; 00928 } 00929 00930 return true; 00931 00932 fail_close: 00933 server_ptr->engine->Close(); 00934 00935 fail_delete: 00936 delete server_ptr->engine; 00937 server_ptr->engine = NULL; 00938 00939 fail_unregister: 00940 jack_log("cleaning up shared memory"); 00941 00942 jack_cleanup_shm(); 00943 00944 jack_log("cleaning up files"); 00945 00946 JackTools::CleanupFiles(server_ptr->name.str); 00947 00948 jack_log("unregistering server `%s'", server_ptr->name.str); 00949 00950 jack_unregister_server(server_ptr->name.str); 00951 00952 fail: 00953 return false; 00954 } 00955 00956 EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr) 00957 { 00958 return driver_ptr->desc_ptr->name; 00959 } 00960 00961 EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr) 00962 { 00963 return driver_ptr->parameters; 00964 } 00965 00966 EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr) 00967 { 00968 return driver_ptr->desc_ptr; 00969 } 00970 00971 EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr) 00972 { 00973 return parameter_ptr->name; 00974 } 00975 00976 EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr) 00977 { 00978 return parameter_ptr->short_description; 00979 } 00980 00981 EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr) 00982 { 00983 return parameter_ptr->long_description; 00984 } 00985 00986 EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr) 00987 { 00988 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0; 00989 } 00990 00991 EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr) 00992 { 00993 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0; 00994 } 00995 00996 EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr) 00997 { 00998 if (!jackctl_parameter_has_enum_constraint(parameter_ptr)) 00999 { 01000 return 0; 01001 } 01002 01003 return parameter_ptr->constraint_ptr->constraint.enumeration.count; 01004 } 01005 01006 EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index) 01007 { 01008 jack_driver_param_value_t * value_ptr; 01009 union jackctl_parameter_value jackctl_value; 01010 01011 value_ptr = ¶meter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value; 01012 01013 switch (parameter_ptr->type) 01014 { 01015 case JackParamInt: 01016 jackctl_value.i = value_ptr->i; 01017 break; 01018 case JackParamUInt: 01019 jackctl_value.ui = value_ptr->ui; 01020 break; 01021 case JackParamChar: 01022 jackctl_value.c = value_ptr->c; 01023 break; 01024 case JackParamString: 01025 strcpy(jackctl_value.str, value_ptr->str); 01026 break; 01027 default: 01028 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type); 01029 assert(0); 01030 } 01031 01032 return jackctl_value; 01033 } 01034 01035 EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index) 01036 { 01037 return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc; 01038 } 01039 01040 EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr) 01041 { 01042 switch (parameter_ptr->type) 01043 { 01044 case JackParamInt: 01045 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i; 01046 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i; 01047 return; 01048 case JackParamUInt: 01049 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui; 01050 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui; 01051 return; 01052 default: 01053 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type); 01054 assert(0); 01055 } 01056 } 01057 01058 EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr) 01059 { 01060 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0; 01061 } 01062 01063 EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr) 01064 { 01065 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0; 01066 } 01067 01068 EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr) 01069 { 01070 return parameter_ptr->type; 01071 } 01072 01073 EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr) 01074 { 01075 return parameter_ptr->id; 01076 } 01077 01078 EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr) 01079 { 01080 return parameter_ptr->is_set; 01081 } 01082 01083 EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr) 01084 { 01085 return *parameter_ptr->value_ptr; 01086 } 01087 01088 EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr) 01089 { 01090 if (!parameter_ptr->is_set) 01091 { 01092 return true; 01093 } 01094 01095 parameter_ptr->is_set = false; 01096 01097 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr; 01098 01099 return true; 01100 } 01101 01102 EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr) 01103 { 01104 bool new_driver_parameter; 01105 01106 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */ 01107 if (parameter_ptr->driver_ptr != NULL) 01108 { 01109 /* jack_info("setting driver parameter %p ...", parameter_ptr); */ 01110 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL; 01111 if (new_driver_parameter) 01112 { 01113 /* jack_info("new driver parameter..."); */ 01114 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t)); 01115 if (parameter_ptr->driver_parameter_ptr == NULL) 01116 { 01117 jack_error ("Allocation of jack_driver_param_t structure failed"); 01118 return false; 01119 } 01120 01121 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id; 01122 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); 01123 } 01124 01125 switch (parameter_ptr->type) 01126 { 01127 case JackParamInt: 01128 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i; 01129 break; 01130 case JackParamUInt: 01131 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui; 01132 break; 01133 case JackParamChar: 01134 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c; 01135 break; 01136 case JackParamString: 01137 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str); 01138 break; 01139 case JackParamBool: 01140 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b; 01141 break; 01142 default: 01143 jack_error("unknown parameter type %i", (int)parameter_ptr->type); 01144 assert(0); 01145 01146 if (new_driver_parameter) 01147 { 01148 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); 01149 } 01150 01151 return false; 01152 } 01153 } 01154 01155 parameter_ptr->is_set = true; 01156 *parameter_ptr->value_ptr = *value_ptr; 01157 01158 return true; 01159 } 01160 01161 EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr) 01162 { 01163 return *parameter_ptr->default_value_ptr; 01164 } 01165 01166 // Internals clients 01167 01168 EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr) 01169 { 01170 return server_ptr->internals; 01171 } 01172 01173 EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr) 01174 { 01175 return internal_ptr->desc_ptr->name; 01176 } 01177 01178 EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr) 01179 { 01180 return internal_ptr->parameters; 01181 } 01182 01183 EXPORT bool jackctl_server_load_internal( 01184 jackctl_server * server_ptr, 01185 jackctl_internal * internal) 01186 { 01187 int status; 01188 if (server_ptr->engine != NULL) { 01189 server_ptr->engine->InternalClientLoad(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, &status); 01190 return (internal->refnum > 0); 01191 } else { 01192 return false; 01193 } 01194 } 01195 01196 EXPORT bool jackctl_server_unload_internal( 01197 jackctl_server * server_ptr, 01198 jackctl_internal * internal) 01199 { 01200 int status; 01201 if (server_ptr->engine != NULL && internal->refnum > 0) { 01202 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0); 01203 } else { 01204 return false; 01205 } 01206 } 01207 01208 EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01209 { 01210 if (server_ptr->engine != NULL) { 01211 driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); 01212 return (driver_ptr->info != 0); 01213 } else { 01214 return false; 01215 } 01216 } 01217 01218 EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01219 { 01220 if (server_ptr->engine != NULL) { 01221 server_ptr->engine->RemoveSlave(driver_ptr->info); 01222 delete driver_ptr->info; 01223 return true; 01224 } else { 01225 return false; 01226 } 01227 } 01228 01229 EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01230 { 01231 if (server_ptr->engine != NULL) { 01232 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0); 01233 } else { 01234 return false; 01235 } 01236 } 01237