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