00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
00070 union jackctl_parameter_value name;
00071 union jackctl_parameter_value default_name;
00072
00073
00074 union jackctl_parameter_value realtime;
00075 union jackctl_parameter_value default_realtime;
00076
00077
00078 union jackctl_parameter_value realtime_priority;
00079 union jackctl_parameter_value default_realtime_priority;
00080
00081
00082 union jackctl_parameter_value temporary;
00083 union jackctl_parameter_value default_temporary;
00084
00085
00086 union jackctl_parameter_value verbose;
00087 union jackctl_parameter_value default_verbose;
00088
00089
00090 union jackctl_parameter_value client_timeout;
00091 union jackctl_parameter_value default_client_timeout;
00092
00093
00094 union jackctl_parameter_value clock_source;
00095 union jackctl_parameter_value default_clock_source;
00096
00097
00098 union jackctl_parameter_value port_max;
00099 union jackctl_parameter_value default_port_max;
00100
00101
00102 union jackctl_parameter_value replace_registry;
00103 union jackctl_parameter_value default_replace_registry;
00104
00105
00106 union jackctl_parameter_value sync;
00107 union jackctl_parameter_value default_sync;
00108
00109
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
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
00317
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
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
00588
00589
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
00604
00605
00606
00607 setsid();
00608
00609 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
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
00645
00646
00647 sigaddset(&sigmask.signals, SIGUSR1);
00648 #endif
00649 sigaddset(&sigmask.signals, SIGUSR2);
00650
00651
00652
00653
00654
00655 pthread_sigmask(SIG_BLOCK, &sigmask.signals, 0);
00656
00657
00658
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
00694 break;
00695 case SIGUSR2:
00696
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
00709
00710
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
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
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
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
01030
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;
01036 }
01037
01038
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
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
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
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