Jack2 1.9.7

JackControlAPI.cpp

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