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