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