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