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