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

Generated for Jack2 by doxygen 1.7.3