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