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