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