Jack2 1.9.8
|
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 JSList * infos; 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 unsigned int i; 00219 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 driver_ptr->infos = NULL; 00313 00314 if (!jackctl_add_driver_parameters(driver_ptr)) 00315 { 00316 assert(driver_ptr->parameters == NULL); 00317 free(driver_ptr); 00318 goto next; 00319 } 00320 00321 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr); 00322 00323 next: 00324 node_ptr = descriptor_node_ptr; 00325 descriptor_node_ptr = descriptor_node_ptr->next; 00326 free(node_ptr); 00327 } 00328 00329 return true; 00330 } 00331 00332 static 00333 void 00334 jackctl_server_free_drivers( 00335 struct jackctl_server * server_ptr) 00336 { 00337 JSList * next_node_ptr; 00338 struct jackctl_driver * driver_ptr; 00339 00340 while (server_ptr->drivers) 00341 { 00342 next_node_ptr = server_ptr->drivers->next; 00343 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data; 00344 00345 jackctl_free_driver_parameters(driver_ptr); 00346 free(driver_ptr->desc_ptr->params); 00347 free(driver_ptr->desc_ptr); 00348 free(driver_ptr); 00349 00350 free(server_ptr->drivers); 00351 server_ptr->drivers = next_node_ptr; 00352 } 00353 } 00354 00355 static int 00356 jackctl_internals_load( 00357 struct jackctl_server * server_ptr) 00358 { 00359 struct jackctl_internal * internal_ptr; 00360 JSList *node_ptr; 00361 JSList *descriptor_node_ptr; 00362 00363 descriptor_node_ptr = jack_internals_load(NULL); 00364 if (descriptor_node_ptr == NULL) 00365 { 00366 jack_error("could not find any internals in driver directory!"); 00367 return false; 00368 } 00369 00370 while (descriptor_node_ptr != NULL) 00371 { 00372 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal)); 00373 if (internal_ptr == NULL) 00374 { 00375 jack_error("memory allocation of jackctl_driver structure failed."); 00376 goto next; 00377 } 00378 00379 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data; 00380 internal_ptr->parameters = NULL; 00381 internal_ptr->set_parameters = NULL; 00382 internal_ptr->refnum = -1; 00383 00384 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr)) 00385 { 00386 assert(internal_ptr->parameters == NULL); 00387 free(internal_ptr); 00388 goto next; 00389 } 00390 00391 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr); 00392 00393 next: 00394 node_ptr = descriptor_node_ptr; 00395 descriptor_node_ptr = descriptor_node_ptr->next; 00396 free(node_ptr); 00397 } 00398 00399 return true; 00400 } 00401 00402 static 00403 void 00404 jackctl_server_free_internals( 00405 struct jackctl_server * server_ptr) 00406 { 00407 JSList * next_node_ptr; 00408 struct jackctl_internal * internal_ptr; 00409 00410 while (server_ptr->internals) 00411 { 00412 next_node_ptr = server_ptr->internals->next; 00413 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data; 00414 00415 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr); 00416 free(internal_ptr->desc_ptr->params); 00417 free(internal_ptr->desc_ptr); 00418 free(internal_ptr); 00419 00420 free(server_ptr->internals); 00421 server_ptr->internals = next_node_ptr; 00422 } 00423 } 00424 00425 static 00426 void 00427 jackctl_server_free_parameters( 00428 struct jackctl_server * server_ptr) 00429 { 00430 JSList * next_node_ptr; 00431 00432 while (server_ptr->parameters) 00433 { 00434 next_node_ptr = server_ptr->parameters->next; 00435 free(server_ptr->parameters->data); 00436 free(server_ptr->parameters); 00437 server_ptr->parameters = next_node_ptr; 00438 } 00439 } 00440 00441 #ifdef WIN32 00442 00443 static HANDLE waitEvent; 00444 00445 static void do_nothing_handler(int signum) 00446 { 00447 printf("jack main caught signal %d\n", signum); 00448 (void) signal(SIGINT, SIG_DFL); 00449 SetEvent(waitEvent); 00450 } 00451 00452 sigset_t 00453 jackctl_setup_signals( 00454 unsigned int flags) 00455 { 00456 if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { 00457 jack_error("CreateEvent fails err = %ld", GetLastError()); 00458 return 0; 00459 } 00460 00461 (void) signal(SIGINT, do_nothing_handler); 00462 (void) signal(SIGABRT, do_nothing_handler); 00463 (void) signal(SIGTERM, do_nothing_handler); 00464 00465 return (sigset_t)waitEvent; 00466 } 00467 00468 void jackctl_wait_signals(sigset_t signals) 00469 { 00470 if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) { 00471 jack_error("WaitForSingleObject fails err = %ld", GetLastError()); 00472 } 00473 } 00474 00475 #else 00476 00477 static 00478 void 00479 do_nothing_handler(int sig) 00480 { 00481 /* this is used by the child (active) process, but it never 00482 gets called unless we are already shutting down after 00483 another signal. 00484 */ 00485 char buf[64]; 00486 snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig); 00487 } 00488 00489 SERVER_EXPORT sigset_t 00490 jackctl_setup_signals( 00491 unsigned int flags) 00492 { 00493 sigset_t signals; 00494 sigset_t allsignals; 00495 struct sigaction action; 00496 int i; 00497 00498 /* ensure that we are in our own process group so that 00499 kill (SIG, -pgrp) does the right thing. 00500 */ 00501 00502 setsid(); 00503 00504 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 00505 00506 /* what's this for? 00507 00508 POSIX says that signals are delivered like this: 00509 00510 * if a thread has blocked that signal, it is not 00511 a candidate to receive the signal. 00512 * of all threads not blocking the signal, pick 00513 one at random, and deliver the signal. 00514 00515 this means that a simple-minded multi-threaded program can 00516 expect to get POSIX signals delivered randomly to any one 00517 of its threads, 00518 00519 here, we block all signals that we think we might receive 00520 and want to catch. all "child" threads will inherit this 00521 setting. if we create a thread that calls sigwait() on the 00522 same set of signals, implicitly unblocking all those 00523 signals. any of those signals that are delivered to the 00524 process will be delivered to that thread, and that thread 00525 alone. this makes cleanup for a signal-driven exit much 00526 easier, since we know which thread is doing it and more 00527 importantly, we are free to call async-unsafe functions, 00528 because the code is executing in normal thread context 00529 after a return from sigwait(). 00530 */ 00531 00532 sigemptyset(&signals); 00533 sigaddset(&signals, SIGHUP); 00534 sigaddset(&signals, SIGINT); 00535 sigaddset(&signals, SIGQUIT); 00536 sigaddset(&signals, SIGPIPE); 00537 sigaddset(&signals, SIGTERM); 00538 sigaddset(&signals, SIGUSR1); 00539 sigaddset(&signals, SIGUSR2); 00540 00541 /* all child threads will inherit this mask unless they 00542 * explicitly reset it 00543 */ 00544 00545 pthread_sigmask(SIG_BLOCK, &signals, 0); 00546 00547 /* install a do-nothing handler because otherwise pthreads 00548 behaviour is undefined when we enter sigwait. 00549 */ 00550 00551 sigfillset(&allsignals); 00552 action.sa_handler = do_nothing_handler; 00553 action.sa_mask = allsignals; 00554 action.sa_flags = SA_RESTART|SA_RESETHAND; 00555 00556 for (i = 1; i < NSIG; i++) 00557 { 00558 if (sigismember (&signals, i)) 00559 { 00560 sigaction(i, &action, 0); 00561 } 00562 } 00563 00564 return signals; 00565 } 00566 00567 SERVER_EXPORT void 00568 jackctl_wait_signals(sigset_t signals) 00569 { 00570 int sig; 00571 bool waiting = true; 00572 00573 while (waiting) { 00574 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check 00575 sigwait(&signals); 00576 #else 00577 sigwait(&signals, &sig); 00578 #endif 00579 fprintf(stderr, "jack main caught signal %d\n", sig); 00580 00581 switch (sig) { 00582 case SIGUSR1: 00583 //jack_dump_configuration(engine, 1); 00584 break; 00585 case SIGUSR2: 00586 // driver exit 00587 waiting = false; 00588 break; 00589 case SIGTTOU: 00590 break; 00591 default: 00592 waiting = false; 00593 break; 00594 } 00595 } 00596 00597 if (sig != SIGSEGV) { 00598 // unblock signals so we can see them during shutdown. 00599 // this will help prod developers not to lose sight of 00600 // bugs that cause segfaults etc. during shutdown. 00601 sigprocmask(SIG_UNBLOCK, &signals, 0); 00602 } 00603 } 00604 #endif 00605 00606 static 00607 jack_driver_param_constraint_desc_t * 00608 get_realtime_priority_constraint() 00609 { 00610 jack_driver_param_constraint_desc_t * constraint_ptr; 00611 int min, max; 00612 00613 if (!jack_get_thread_realtime_priority_range(&min, &max)) 00614 { 00615 return NULL; 00616 } 00617 00618 //jack_info("realtime priority range is (%d,%d)", min, max); 00619 00620 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t)); 00621 if (constraint_ptr == NULL) 00622 { 00623 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure."); 00624 return NULL; 00625 } 00626 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE; 00627 00628 constraint_ptr->constraint.range.min.i = min; 00629 constraint_ptr->constraint.range.max.i = max; 00630 00631 return constraint_ptr; 00632 } 00633 00634 SERVER_EXPORT jackctl_server_t * jackctl_server_create( 00635 bool (* on_device_acquire)(const char * device_name), 00636 void (* on_device_release)(const char * device_name)) 00637 { 00638 struct jackctl_server * server_ptr; 00639 union jackctl_parameter_value value; 00640 00641 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server)); 00642 if (server_ptr == NULL) 00643 { 00644 jack_error("Cannot allocate memory for jackctl_server structure."); 00645 goto fail; 00646 } 00647 00648 server_ptr->drivers = NULL; 00649 server_ptr->internals = NULL; 00650 server_ptr->parameters = NULL; 00651 server_ptr->engine = NULL; 00652 00653 strcpy(value.str, JACK_DEFAULT_SERVER_NAME); 00654 if (jackctl_add_parameter( 00655 &server_ptr->parameters, 00656 "name", 00657 "Server name to use.", 00658 "", 00659 JackParamString, 00660 &server_ptr->name, 00661 &server_ptr->default_name, 00662 value) == NULL) 00663 { 00664 goto fail_free_parameters; 00665 } 00666 00667 value.b = true; 00668 if (jackctl_add_parameter( 00669 &server_ptr->parameters, 00670 "realtime", 00671 "Whether to use realtime mode.", 00672 "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.", 00673 JackParamBool, 00674 &server_ptr->realtime, 00675 &server_ptr->default_realtime, 00676 value) == NULL) 00677 { 00678 goto fail_free_parameters; 00679 } 00680 00681 value.i = 10; 00682 if (jackctl_add_parameter( 00683 &server_ptr->parameters, 00684 "realtime-priority", 00685 "Scheduler priority when running in realtime mode.", 00686 "", 00687 JackParamInt, 00688 &server_ptr->realtime_priority, 00689 &server_ptr->default_realtime_priority, 00690 value, 00691 get_realtime_priority_constraint()) == NULL) 00692 { 00693 goto fail_free_parameters; 00694 } 00695 00696 value.b = false; 00697 if (jackctl_add_parameter( 00698 &server_ptr->parameters, 00699 "temporary", 00700 "Exit once all clients have closed their connections.", 00701 "", 00702 JackParamBool, 00703 &server_ptr->temporary, 00704 &server_ptr->default_temporary, 00705 value) == NULL) 00706 { 00707 goto fail_free_parameters; 00708 } 00709 00710 value.b = false; 00711 if (jackctl_add_parameter( 00712 &server_ptr->parameters, 00713 "verbose", 00714 "Verbose mode.", 00715 "", 00716 JackParamBool, 00717 &server_ptr->verbose, 00718 &server_ptr->default_verbose, 00719 value) == NULL) 00720 { 00721 goto fail_free_parameters; 00722 } 00723 00724 value.i = 0; 00725 if (jackctl_add_parameter( 00726 &server_ptr->parameters, 00727 "client-timeout", 00728 "Client timeout limit in milliseconds.", 00729 "", 00730 JackParamInt, 00731 &server_ptr->client_timeout, 00732 &server_ptr->default_client_timeout, 00733 value) == NULL) 00734 { 00735 goto fail_free_parameters; 00736 } 00737 00738 value.ui = 0; 00739 if (jackctl_add_parameter( 00740 &server_ptr->parameters, 00741 "clock-source", 00742 "Clocksource type : c(ycle) | h(pet) | s(ystem).", 00743 "", 00744 JackParamUInt, 00745 &server_ptr->clock_source, 00746 &server_ptr->default_clock_source, 00747 value) == NULL) 00748 { 00749 goto fail_free_parameters; 00750 } 00751 00752 value.ui = PORT_NUM; 00753 if (jackctl_add_parameter( 00754 &server_ptr->parameters, 00755 "port-max", 00756 "Maximum number of ports.", 00757 "", 00758 JackParamUInt, 00759 &server_ptr->port_max, 00760 &server_ptr->default_port_max, 00761 value) == NULL) 00762 { 00763 goto fail_free_parameters; 00764 } 00765 00766 value.b = false; 00767 if (jackctl_add_parameter( 00768 &server_ptr->parameters, 00769 "replace-registry", 00770 "Replace shared memory registry.", 00771 "", 00772 JackParamBool, 00773 &server_ptr->replace_registry, 00774 &server_ptr->default_replace_registry, 00775 value) == NULL) 00776 { 00777 goto fail_free_parameters; 00778 } 00779 00780 value.b = false; 00781 if (jackctl_add_parameter( 00782 &server_ptr->parameters, 00783 "sync", 00784 "Use server synchronous mode.", 00785 "", 00786 JackParamBool, 00787 &server_ptr->sync, 00788 &server_ptr->default_sync, 00789 value) == NULL) 00790 { 00791 goto fail_free_parameters; 00792 } 00793 00794 JackServerGlobals::on_device_acquire = on_device_acquire; 00795 JackServerGlobals::on_device_release = on_device_release; 00796 00797 if (!jackctl_drivers_load(server_ptr)) 00798 { 00799 goto fail_free_parameters; 00800 } 00801 00802 /* Allowed to fail */ 00803 jackctl_internals_load(server_ptr); 00804 00805 return server_ptr; 00806 00807 fail_free_parameters: 00808 jackctl_server_free_parameters(server_ptr); 00809 00810 free(server_ptr); 00811 00812 fail: 00813 return NULL; 00814 } 00815 00816 SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr) 00817 { 00818 if (server_ptr) { 00819 jackctl_server_free_drivers(server_ptr); 00820 jackctl_server_free_internals(server_ptr); 00821 jackctl_server_free_parameters(server_ptr); 00822 free(server_ptr); 00823 } 00824 } 00825 00826 SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr) 00827 { 00828 return (server_ptr) ? server_ptr->drivers : NULL; 00829 } 00830 00831 SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr) 00832 { 00833 if (server_ptr) { 00834 server_ptr->engine->Stop(); 00835 return true; 00836 } else { 00837 return false; 00838 } 00839 } 00840 00841 SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr) 00842 { 00843 if (server_ptr) { 00844 server_ptr->engine->Close(); 00845 delete server_ptr->engine; 00846 00847 /* clean up shared memory and files from this server instance */ 00848 jack_log("cleaning up shared memory"); 00849 00850 jack_cleanup_shm(); 00851 00852 jack_log("cleaning up files"); 00853 00854 JackTools::CleanupFiles(server_ptr->name.str); 00855 00856 jack_log("unregistering server `%s'", server_ptr->name.str); 00857 00858 jack_unregister_server(server_ptr->name.str); 00859 00860 server_ptr->engine = NULL; 00861 00862 return true; 00863 } else { 00864 return false; 00865 } 00866 } 00867 00868 SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr) 00869 { 00870 return (server_ptr) ? server_ptr->parameters : NULL; 00871 } 00872 00873 SERVER_EXPORT bool 00874 jackctl_server_open( 00875 jackctl_server *server_ptr, 00876 jackctl_driver *driver_ptr) 00877 { 00878 try { 00879 00880 if (!server_ptr || !driver_ptr) { 00881 return false; 00882 } 00883 00884 int rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b); 00885 switch (rc) 00886 { 00887 case EEXIST: 00888 jack_error("`%s' server already active", server_ptr->name.str); 00889 goto fail; 00890 case ENOSPC: 00891 jack_error("too many servers already active"); 00892 goto fail; 00893 case ENOMEM: 00894 jack_error("no access to shm registry"); 00895 goto fail; 00896 } 00897 00898 jack_log("server `%s' registered", server_ptr->name.str); 00899 00900 /* clean up shared memory and files from any previous 00901 * instance of this server name */ 00902 jack_cleanup_shm(); 00903 JackTools::CleanupFiles(server_ptr->name.str); 00904 00905 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) { 00906 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */ 00907 } 00908 00909 /* check port max value before allocating server */ 00910 if (server_ptr->port_max.ui > PORT_NUM_MAX) { 00911 jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX); 00912 goto fail; 00913 } 00914 00915 /* get the engine/driver started */ 00916 server_ptr->engine = new JackServer( 00917 server_ptr->sync.b, 00918 server_ptr->temporary.b, 00919 server_ptr->client_timeout.i, 00920 server_ptr->realtime.b, 00921 server_ptr->realtime_priority.i, 00922 server_ptr->port_max.ui, 00923 server_ptr->verbose.b, 00924 (jack_timer_type_t)server_ptr->clock_source.ui, 00925 server_ptr->name.str); 00926 if (server_ptr->engine == NULL) 00927 { 00928 jack_error("Failed to create new JackServer object"); 00929 goto fail_unregister; 00930 } 00931 00932 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters); 00933 if (rc < 0) 00934 { 00935 jack_error("JackServer::Open() failed with %d", rc); 00936 goto fail_delete; 00937 } 00938 00939 return true; 00940 00941 } catch (std::exception e) { 00942 jack_error("jackctl_server_open error..."); 00943 } 00944 00945 fail_delete: 00946 delete server_ptr->engine; 00947 server_ptr->engine = NULL; 00948 00949 fail_unregister: 00950 jack_log("cleaning up shared memory"); 00951 00952 jack_cleanup_shm(); 00953 00954 jack_log("cleaning up files"); 00955 00956 JackTools::CleanupFiles(server_ptr->name.str); 00957 00958 jack_log("unregistering server `%s'", server_ptr->name.str); 00959 00960 jack_unregister_server(server_ptr->name.str); 00961 00962 fail: 00963 return false; 00964 } 00965 00966 SERVER_EXPORT bool 00967 jackctl_server_start( 00968 jackctl_server *server_ptr) 00969 { 00970 if (!server_ptr) { 00971 return false; 00972 } else { 00973 int rc = server_ptr->engine->Start(); 00974 bool result = rc >= 0; 00975 if (! result) 00976 { 00977 jack_error("JackServer::Start() failed with %d", rc); 00978 } 00979 return result; 00980 } 00981 } 00982 00983 SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr) 00984 { 00985 return (driver_ptr) ? driver_ptr->desc_ptr->name : NULL; 00986 } 00987 00988 SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr) 00989 { 00990 return (driver_ptr) ? (jackctl_driver_type_t)driver_ptr->desc_ptr->type : (jackctl_driver_type_t)0; 00991 } 00992 00993 SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr) 00994 { 00995 return (driver_ptr) ? driver_ptr->parameters : NULL; 00996 } 00997 00998 SERVER_EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr) 00999 { 01000 return (driver_ptr) ? driver_ptr->desc_ptr : NULL; 01001 } 01002 01003 SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr) 01004 { 01005 return (parameter_ptr) ? parameter_ptr->name : NULL; 01006 } 01007 01008 SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr) 01009 { 01010 return (parameter_ptr) ? parameter_ptr->short_description : NULL; 01011 } 01012 01013 SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr) 01014 { 01015 return (parameter_ptr) ? parameter_ptr->long_description : NULL; 01016 } 01017 01018 SERVER_EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr) 01019 { 01020 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0) : false; 01021 } 01022 01023 SERVER_EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr) 01024 { 01025 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0): false; 01026 } 01027 01028 SERVER_EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr) 01029 { 01030 if (!parameter_ptr) { 01031 return NULL; 01032 } 01033 01034 if (!jackctl_parameter_has_enum_constraint(parameter_ptr)) 01035 { 01036 return 0; 01037 } 01038 01039 return parameter_ptr->constraint_ptr->constraint.enumeration.count; 01040 } 01041 01042 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index) 01043 { 01044 jack_driver_param_value_t * value_ptr; 01045 union jackctl_parameter_value jackctl_value; 01046 01047 if (!parameter_ptr) { 01048 memset(&jackctl_value, 0, sizeof(jackctl_value)); 01049 return jackctl_value; 01050 } 01051 01052 value_ptr = ¶meter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value; 01053 01054 switch (parameter_ptr->type) 01055 { 01056 case JackParamInt: 01057 jackctl_value.i = value_ptr->i; 01058 break; 01059 case JackParamUInt: 01060 jackctl_value.ui = value_ptr->ui; 01061 break; 01062 case JackParamChar: 01063 jackctl_value.c = value_ptr->c; 01064 break; 01065 case JackParamString: 01066 strcpy(jackctl_value.str, value_ptr->str); 01067 break; 01068 default: 01069 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type); 01070 assert(0); 01071 } 01072 01073 return jackctl_value; 01074 } 01075 01076 SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index) 01077 { 01078 return (parameter_ptr) ? parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc : NULL; 01079 } 01080 01081 SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr) 01082 { 01083 if (!parameter_ptr || !min_ptr || !max_ptr) { 01084 return; 01085 } 01086 01087 switch (parameter_ptr->type) 01088 { 01089 case JackParamInt: 01090 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i; 01091 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i; 01092 return; 01093 case JackParamUInt: 01094 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui; 01095 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui; 01096 return; 01097 default: 01098 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type); 01099 assert(0); 01100 } 01101 } 01102 01103 SERVER_EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr) 01104 { 01105 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0) : false; 01106 } 01107 01108 SERVER_EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr) 01109 { 01110 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0) : false; 01111 } 01112 01113 SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr) 01114 { 01115 return (parameter_ptr) ? parameter_ptr->type : (jackctl_param_type_t)0; 01116 } 01117 01118 SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr) 01119 { 01120 return (parameter_ptr) ? parameter_ptr->id : 0; 01121 } 01122 01123 SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr) 01124 { 01125 return (parameter_ptr) ? parameter_ptr->is_set : false; 01126 } 01127 01128 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr) 01129 { 01130 if (parameter_ptr) { 01131 return *parameter_ptr->value_ptr; 01132 } else { 01133 union jackctl_parameter_value jackctl_value; 01134 memset(&jackctl_value, 0, sizeof(jackctl_value)); 01135 return jackctl_value; 01136 } 01137 } 01138 01139 SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr) 01140 { 01141 if (!parameter_ptr) { 01142 return NULL; 01143 } 01144 01145 if (!parameter_ptr->is_set) 01146 { 01147 return true; 01148 } 01149 01150 parameter_ptr->is_set = false; 01151 01152 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr; 01153 01154 return true; 01155 } 01156 01157 SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr) 01158 { 01159 if (!parameter_ptr || !value_ptr) { 01160 return NULL; 01161 } 01162 01163 bool new_driver_parameter; 01164 01165 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */ 01166 if (parameter_ptr->driver_ptr != NULL) 01167 { 01168 /* jack_info("setting driver parameter %p ...", parameter_ptr); */ 01169 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL; 01170 if (new_driver_parameter) 01171 { 01172 /* jack_info("new driver parameter..."); */ 01173 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t)); 01174 if (parameter_ptr->driver_parameter_ptr == NULL) 01175 { 01176 jack_error ("Allocation of jack_driver_param_t structure failed"); 01177 return false; 01178 } 01179 01180 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id; 01181 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); 01182 } 01183 01184 switch (parameter_ptr->type) 01185 { 01186 case JackParamInt: 01187 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i; 01188 break; 01189 case JackParamUInt: 01190 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui; 01191 break; 01192 case JackParamChar: 01193 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c; 01194 break; 01195 case JackParamString: 01196 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str); 01197 break; 01198 case JackParamBool: 01199 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b; 01200 break; 01201 default: 01202 jack_error("unknown parameter type %i", (int)parameter_ptr->type); 01203 assert(0); 01204 01205 if (new_driver_parameter) 01206 { 01207 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr); 01208 } 01209 01210 return false; 01211 } 01212 } 01213 01214 parameter_ptr->is_set = true; 01215 *parameter_ptr->value_ptr = *value_ptr; 01216 01217 return true; 01218 } 01219 01220 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr) 01221 { 01222 if (parameter_ptr) { 01223 return *parameter_ptr->default_value_ptr; 01224 } else { 01225 union jackctl_parameter_value jackctl_value; 01226 memset(&jackctl_value, 0, sizeof(jackctl_value)); 01227 return jackctl_value; 01228 } 01229 } 01230 01231 // Internals clients 01232 01233 SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr) 01234 { 01235 return (server_ptr) ? server_ptr->internals : NULL; 01236 } 01237 01238 SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr) 01239 { 01240 return (internal_ptr) ? internal_ptr->desc_ptr->name : NULL; 01241 } 01242 01243 SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr) 01244 { 01245 return (internal_ptr) ? internal_ptr->parameters : NULL; 01246 } 01247 01248 SERVER_EXPORT bool jackctl_server_load_internal( 01249 jackctl_server * server_ptr, 01250 jackctl_internal * internal) 01251 { 01252 if (!server_ptr || !internal) { 01253 return false; 01254 } 01255 01256 int status; 01257 if (server_ptr->engine != NULL) { 01258 server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, -1, &status); 01259 return (internal->refnum > 0); 01260 } else { 01261 return false; 01262 } 01263 } 01264 01265 SERVER_EXPORT bool jackctl_server_unload_internal( 01266 jackctl_server * server_ptr, 01267 jackctl_internal * internal) 01268 { 01269 if (!server_ptr || !internal) { 01270 return false; 01271 } 01272 01273 int status; 01274 if (server_ptr->engine != NULL && internal->refnum > 0) { 01275 // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload 01276 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0); 01277 } else { 01278 return false; 01279 } 01280 } 01281 01282 SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01283 { 01284 if (server_ptr && server_ptr->engine) { 01285 if (server_ptr->engine->IsRunning()) { 01286 jack_error("cannot add a slave in a running server"); 01287 return false; 01288 } else { 01289 JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters); 01290 if (info) { 01291 driver_ptr->infos = jack_slist_append(driver_ptr->infos, info); 01292 return true; 01293 } else { 01294 return false; 01295 } 01296 } 01297 } else { 01298 return false; 01299 } 01300 } 01301 01302 SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01303 { 01304 if (server_ptr && server_ptr->engine) { 01305 if (server_ptr->engine->IsRunning()) { 01306 jack_error("cannot remove a slave from a running server"); 01307 return false; 01308 } else { 01309 if (driver_ptr->infos) { 01310 JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data; 01311 assert(info); 01312 driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info); 01313 server_ptr->engine->RemoveSlave(info); 01314 delete info; 01315 return true; 01316 } else { 01317 return false; 01318 } 01319 } 01320 } else { 01321 return false; 01322 } 01323 } 01324 01325 SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr) 01326 { 01327 if (server_ptr && server_ptr->engine) { 01328 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0); 01329 } else { 01330 return false; 01331 } 01332 } 01333 01334