Jack2 1.9.6

JackControlAPI.cpp

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