Control API: Enforce driver/internal parameter order.
[jack2.git] / common / JackControlAPI.cpp
blob459905307a6aa8be3f689fce374592bcd48d2672
1 // u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */
2 /*
3 JACK control API implementation
5 Copyright (C) 2008 Nedko Arnaudov
6 Copyright (C) 2008 Grame
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #ifndef WIN32
24 #include <stdint.h>
25 #include <dirent.h>
26 #include <pthread.h>
27 #endif
29 #include "types.h"
30 #include <string.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <assert.h>
34 #include <signal.h>
36 #include "jslist.h"
37 #include "driver_interface.h"
38 #include "JackError.h"
39 #include "JackServer.h"
40 #include "shm.h"
41 #include "JackTools.h"
42 #include "JackControlAPI.h"
43 #include "JackLockedEngine.h"
44 #include "JackConstants.h"
45 #include "JackDriverLoader.h"
46 #include "JackServerGlobals.h"
48 using namespace Jack;
50 struct jackctl_server
52 JSList * drivers;
53 JSList * internals;
54 JSList * parameters;
56 class JackServer * engine;
58 /* string, server name */
59 union jackctl_parameter_value name;
60 union jackctl_parameter_value default_name;
62 /* bool, whether to be "realtime" */
63 union jackctl_parameter_value realtime;
64 union jackctl_parameter_value default_realtime;
66 /* int32_t */
67 union jackctl_parameter_value realtime_priority;
68 union jackctl_parameter_value default_realtime_priority;
70 /* bool, whether to exit once all clients have closed their connections */
71 union jackctl_parameter_value temporary;
72 union jackctl_parameter_value default_temporary;
74 /* bool, whether to be verbose */
75 union jackctl_parameter_value verbose;
76 union jackctl_parameter_value default_verbose;
78 /* int32_t, msecs; if zero, use period size. */
79 union jackctl_parameter_value client_timeout;
80 union jackctl_parameter_value default_client_timeout;
82 /* uint32_t, clock source type */
83 union jackctl_parameter_value clock_source;
84 union jackctl_parameter_value default_clock_source;
86 /* uint32_t, max port number */
87 union jackctl_parameter_value port_max;
88 union jackctl_parameter_value default_port_max;
90 /* bool */
91 union jackctl_parameter_value replace_registry;
92 union jackctl_parameter_value default_replace_registry;
94 /* bool, synchronous or asynchronous engine mode */
95 union jackctl_parameter_value sync;
96 union jackctl_parameter_value default_sync;
99 struct jackctl_driver
101 jack_driver_desc_t * desc_ptr;
102 JSList * parameters;
103 JSList * infos;
106 struct jackctl_internal
108 jack_driver_desc_t * desc_ptr;
109 JSList * parameters;
110 int refnum;
113 struct jackctl_parameter
115 const char * name;
116 const char * short_description;
117 const char * long_description;
118 jackctl_param_type_t type;
119 bool is_set;
120 union jackctl_parameter_value * value_ptr;
121 union jackctl_parameter_value * default_value_ptr;
123 union jackctl_parameter_value value;
124 union jackctl_parameter_value default_value;
125 struct jackctl_driver * driver_ptr;
126 char id;
127 jack_driver_param_constraint_desc_t * constraint_ptr;
130 static
131 struct jackctl_parameter *
132 jackctl_add_parameter(
133 JSList ** parameters_list_ptr_ptr,
134 const char * name,
135 const char * short_description,
136 const char * long_description,
137 jackctl_param_type_t type,
138 union jackctl_parameter_value * value_ptr,
139 union jackctl_parameter_value * default_value_ptr,
140 union jackctl_parameter_value value,
141 jack_driver_param_constraint_desc_t * constraint_ptr = NULL)
143 struct jackctl_parameter * parameter_ptr;
145 parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter));
146 if (parameter_ptr == NULL)
148 jack_error("Cannot allocate memory for jackctl_parameter structure.");
149 goto fail;
152 parameter_ptr->name = name;
153 parameter_ptr->short_description = short_description;
154 parameter_ptr->long_description = long_description;
155 parameter_ptr->type = type;
156 parameter_ptr->is_set = false;
158 if (value_ptr == NULL)
160 value_ptr = &parameter_ptr->value;
163 if (default_value_ptr == NULL)
165 default_value_ptr = &parameter_ptr->default_value;
168 parameter_ptr->value_ptr = value_ptr;
169 parameter_ptr->default_value_ptr = default_value_ptr;
171 *value_ptr = *default_value_ptr = value;
173 parameter_ptr->driver_ptr = NULL;
174 parameter_ptr->id = 0;
175 parameter_ptr->constraint_ptr = constraint_ptr;
177 *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
179 return parameter_ptr;
181 fail:
182 return NULL;
185 static
186 void
187 jackctl_free_driver_parameters(
188 struct jackctl_driver * driver_ptr)
190 JSList * next_node_ptr;
192 while (driver_ptr->parameters)
194 next_node_ptr = driver_ptr->parameters->next;
195 free(driver_ptr->parameters->data);
196 free(driver_ptr->parameters);
197 driver_ptr->parameters = next_node_ptr;
201 static
202 bool
203 jackctl_add_driver_parameters(
204 struct jackctl_driver * driver_ptr)
206 unsigned int i;
208 union jackctl_parameter_value jackctl_value;
209 jackctl_param_type_t jackctl_type;
210 struct jackctl_parameter * parameter_ptr;
211 jack_driver_param_desc_t * descriptor_ptr;
213 for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
215 descriptor_ptr = driver_ptr->desc_ptr->params + i;
217 switch (descriptor_ptr->type)
219 case JackDriverParamInt:
220 jackctl_type = JackParamInt;
221 jackctl_value.i = descriptor_ptr->value.i;
222 break;
223 case JackDriverParamUInt:
224 jackctl_type = JackParamUInt;
225 jackctl_value.ui = descriptor_ptr->value.ui;
226 break;
227 case JackDriverParamChar:
228 jackctl_type = JackParamChar;
229 jackctl_value.c = descriptor_ptr->value.c;
230 break;
231 case JackDriverParamString:
232 jackctl_type = JackParamString;
233 strcpy(jackctl_value.str, descriptor_ptr->value.str);
234 break;
235 case JackDriverParamBool:
236 jackctl_type = JackParamBool;
237 jackctl_value.b = descriptor_ptr->value.i;
238 break;
239 default:
240 jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type);
241 assert(0);
242 goto fail;
245 parameter_ptr = jackctl_add_parameter(
246 &driver_ptr->parameters,
247 descriptor_ptr->name,
248 descriptor_ptr->short_desc,
249 descriptor_ptr->long_desc,
250 jackctl_type,
251 NULL,
252 NULL,
253 jackctl_value,
254 descriptor_ptr->constraint);
256 if (parameter_ptr == NULL)
258 goto fail;
261 parameter_ptr->driver_ptr = driver_ptr;
262 parameter_ptr->id = descriptor_ptr->character;
265 return true;
267 fail:
268 jackctl_free_driver_parameters(driver_ptr);
270 return false;
273 /* destroy jack_driver_param_desc_t list created by jackctl_create_param_list() */
274 static void
275 jackctl_destroy_param_list(
276 JSList * params)
278 JSList * next;
280 while (params)
282 next = params->next;
283 free(params->data);
284 free(params);
285 params = next;
289 /* for drivers and internals are configured through jack_driver_param_t JSList */
290 /* this function creates such list from a jackctl_parameter list */
291 static JSList *
292 jackctl_create_param_list(
293 const JSList * paramlist)
295 jackctl_parameter * param_ptr;
296 jack_driver_param_t * retparam_ptr;
297 JSList * retparamlist;
299 retparamlist = NULL;
300 while (paramlist != NULL)
302 param_ptr = (jackctl_parameter *)paramlist->data;
303 if (param_ptr->is_set)
305 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
306 retparam_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t));
307 if (retparam_ptr == NULL)
309 jack_error ("Allocation of jack_driver_param_t structure failed");
310 goto destroy;
313 retparam_ptr->character = param_ptr->id;
315 switch (param_ptr->type)
317 case JackParamInt:
318 retparam_ptr->value.i = param_ptr->value_ptr->i;
319 break;
320 case JackParamUInt:
321 retparam_ptr->value.ui = param_ptr->value_ptr->ui;
322 break;
323 case JackParamChar:
324 retparam_ptr->value.c = param_ptr->value_ptr->c;
325 break;
326 case JackParamString:
327 strcpy(retparam_ptr->value.str, param_ptr->value_ptr->str);
328 break;
329 case JackParamBool:
330 retparam_ptr->value.i = param_ptr->value_ptr->b;
331 break;
332 default:
333 jack_error("unknown parameter type %i", (int)param_ptr->type);
334 assert(0);
335 goto free;
338 retparamlist = jack_slist_append(retparamlist, retparam_ptr);
341 paramlist = paramlist->next;
344 return retparamlist;
346 free:
347 free(retparam_ptr);
348 destroy:
349 jackctl_destroy_param_list(retparamlist);
350 return NULL;
353 static int
354 jackctl_drivers_load(
355 struct jackctl_server * server_ptr)
357 struct jackctl_driver * driver_ptr;
358 JSList *node_ptr;
359 JSList *descriptor_node_ptr;
361 descriptor_node_ptr = jack_drivers_load(NULL);
362 if (descriptor_node_ptr == NULL)
364 jack_error("could not find any drivers in driver directory!");
365 return false;
368 while (descriptor_node_ptr != NULL)
370 driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver));
371 if (driver_ptr == NULL)
373 jack_error("memory allocation of jackctl_driver structure failed.");
374 goto next;
377 driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
378 driver_ptr->parameters = NULL;
379 driver_ptr->infos = NULL;
381 if (!jackctl_add_driver_parameters(driver_ptr))
383 assert(driver_ptr->parameters == NULL);
384 free(driver_ptr);
385 goto next;
388 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
390 next:
391 node_ptr = descriptor_node_ptr;
392 descriptor_node_ptr = descriptor_node_ptr->next;
393 free(node_ptr);
396 return true;
399 static
400 void
401 jackctl_server_free_drivers(
402 struct jackctl_server * server_ptr)
404 JSList * next_node_ptr;
405 struct jackctl_driver * driver_ptr;
407 while (server_ptr->drivers)
409 next_node_ptr = server_ptr->drivers->next;
410 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
412 jackctl_free_driver_parameters(driver_ptr);
413 free(driver_ptr->desc_ptr->params);
414 free(driver_ptr->desc_ptr);
415 free(driver_ptr);
417 free(server_ptr->drivers);
418 server_ptr->drivers = next_node_ptr;
422 static int
423 jackctl_internals_load(
424 struct jackctl_server * server_ptr)
426 struct jackctl_internal * internal_ptr;
427 JSList *node_ptr;
428 JSList *descriptor_node_ptr;
430 descriptor_node_ptr = jack_internals_load(NULL);
431 if (descriptor_node_ptr == NULL)
433 jack_error("could not find any internals in driver directory!");
434 return false;
437 while (descriptor_node_ptr != NULL)
439 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal));
440 if (internal_ptr == NULL)
442 jack_error("memory allocation of jackctl_driver structure failed.");
443 goto next;
446 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
447 internal_ptr->parameters = NULL;
448 internal_ptr->refnum = -1;
450 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr))
452 assert(internal_ptr->parameters == NULL);
453 free(internal_ptr);
454 goto next;
457 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr);
459 next:
460 node_ptr = descriptor_node_ptr;
461 descriptor_node_ptr = descriptor_node_ptr->next;
462 free(node_ptr);
465 return true;
468 static
469 void
470 jackctl_server_free_internals(
471 struct jackctl_server * server_ptr)
473 JSList * next_node_ptr;
474 struct jackctl_internal * internal_ptr;
476 while (server_ptr->internals)
478 next_node_ptr = server_ptr->internals->next;
479 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data;
481 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr);
482 free(internal_ptr->desc_ptr->params);
483 free(internal_ptr->desc_ptr);
484 free(internal_ptr);
486 free(server_ptr->internals);
487 server_ptr->internals = next_node_ptr;
491 static
492 void
493 jackctl_server_free_parameters(
494 struct jackctl_server * server_ptr)
496 JSList * next_node_ptr;
498 while (server_ptr->parameters)
500 next_node_ptr = server_ptr->parameters->next;
501 free(server_ptr->parameters->data);
502 free(server_ptr->parameters);
503 server_ptr->parameters = next_node_ptr;
507 #ifdef WIN32
509 static HANDLE waitEvent;
511 static void do_nothing_handler(int signum)
513 printf("jack main caught signal %d\n", signum);
514 (void) signal(SIGINT, SIG_DFL);
515 SetEvent(waitEvent);
518 sigset_t
519 jackctl_setup_signals(
520 unsigned int flags)
522 if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
523 jack_error("CreateEvent fails err = %ld", GetLastError());
524 return 0;
527 (void) signal(SIGINT, do_nothing_handler);
528 (void) signal(SIGABRT, do_nothing_handler);
529 (void) signal(SIGTERM, do_nothing_handler);
531 return (sigset_t)waitEvent;
534 void jackctl_wait_signals(sigset_t signals)
536 if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) {
537 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
541 #else
543 static
544 void
545 do_nothing_handler(int sig)
547 /* this is used by the child (active) process, but it never
548 gets called unless we are already shutting down after
549 another signal.
551 char buf[64];
552 snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig);
555 SERVER_EXPORT sigset_t
556 jackctl_setup_signals(
557 unsigned int flags)
559 sigset_t signals;
560 sigset_t allsignals;
561 struct sigaction action;
562 int i;
564 /* ensure that we are in our own process group so that
565 kill (SIG, -pgrp) does the right thing.
568 setsid();
570 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
572 /* what's this for?
574 POSIX says that signals are delivered like this:
576 * if a thread has blocked that signal, it is not
577 a candidate to receive the signal.
578 * of all threads not blocking the signal, pick
579 one at random, and deliver the signal.
581 this means that a simple-minded multi-threaded program can
582 expect to get POSIX signals delivered randomly to any one
583 of its threads,
585 here, we block all signals that we think we might receive
586 and want to catch. all "child" threads will inherit this
587 setting. if we create a thread that calls sigwait() on the
588 same set of signals, implicitly unblocking all those
589 signals. any of those signals that are delivered to the
590 process will be delivered to that thread, and that thread
591 alone. this makes cleanup for a signal-driven exit much
592 easier, since we know which thread is doing it and more
593 importantly, we are free to call async-unsafe functions,
594 because the code is executing in normal thread context
595 after a return from sigwait().
598 sigemptyset(&signals);
599 sigaddset(&signals, SIGHUP);
600 sigaddset(&signals, SIGINT);
601 sigaddset(&signals, SIGQUIT);
602 sigaddset(&signals, SIGPIPE);
603 sigaddset(&signals, SIGTERM);
604 sigaddset(&signals, SIGUSR1);
605 sigaddset(&signals, SIGUSR2);
607 /* all child threads will inherit this mask unless they
608 * explicitly reset it
611 pthread_sigmask(SIG_BLOCK, &signals, 0);
613 /* install a do-nothing handler because otherwise pthreads
614 behaviour is undefined when we enter sigwait.
617 sigfillset(&allsignals);
618 action.sa_handler = do_nothing_handler;
619 action.sa_mask = allsignals;
620 action.sa_flags = SA_RESTART|SA_RESETHAND;
622 for (i = 1; i < NSIG; i++)
624 if (sigismember (&signals, i))
626 sigaction(i, &action, 0);
630 return signals;
633 SERVER_EXPORT void
634 jackctl_wait_signals(sigset_t signals)
636 int sig;
637 bool waiting = true;
639 while (waiting) {
640 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
641 sigwait(&signals);
642 #else
643 sigwait(&signals, &sig);
644 #endif
645 fprintf(stderr, "jack main caught signal %d\n", sig);
647 switch (sig) {
648 case SIGUSR1:
649 //jack_dump_configuration(engine, 1);
650 break;
651 case SIGUSR2:
652 // driver exit
653 waiting = false;
654 break;
655 case SIGTTOU:
656 break;
657 default:
658 waiting = false;
659 break;
663 if (sig != SIGSEGV) {
664 // unblock signals so we can see them during shutdown.
665 // this will help prod developers not to lose sight of
666 // bugs that cause segfaults etc. during shutdown.
667 sigprocmask(SIG_UNBLOCK, &signals, 0);
670 #endif
672 static
673 jack_driver_param_constraint_desc_t *
674 get_realtime_priority_constraint()
676 jack_driver_param_constraint_desc_t * constraint_ptr;
677 int min, max;
679 if (!jack_get_thread_realtime_priority_range(&min, &max))
681 return NULL;
684 //jack_info("realtime priority range is (%d,%d)", min, max);
686 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
687 if (constraint_ptr == NULL)
689 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
690 return NULL;
692 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
694 constraint_ptr->constraint.range.min.i = min;
695 constraint_ptr->constraint.range.max.i = max;
697 return constraint_ptr;
700 SERVER_EXPORT jackctl_server_t * jackctl_server_create(
701 bool (* on_device_acquire)(const char * device_name),
702 void (* on_device_release)(const char * device_name))
704 struct jackctl_server * server_ptr;
705 union jackctl_parameter_value value;
707 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
708 if (server_ptr == NULL)
710 jack_error("Cannot allocate memory for jackctl_server structure.");
711 goto fail;
714 server_ptr->drivers = NULL;
715 server_ptr->internals = NULL;
716 server_ptr->parameters = NULL;
717 server_ptr->engine = NULL;
719 strcpy(value.str, JACK_DEFAULT_SERVER_NAME);
720 if (jackctl_add_parameter(
721 &server_ptr->parameters,
722 "name",
723 "Server name to use.",
725 JackParamString,
726 &server_ptr->name,
727 &server_ptr->default_name,
728 value) == NULL)
730 goto fail_free_parameters;
733 value.b = true;
734 if (jackctl_add_parameter(
735 &server_ptr->parameters,
736 "realtime",
737 "Whether to use realtime mode.",
738 "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.",
739 JackParamBool,
740 &server_ptr->realtime,
741 &server_ptr->default_realtime,
742 value) == NULL)
744 goto fail_free_parameters;
747 value.i = 10;
748 if (jackctl_add_parameter(
749 &server_ptr->parameters,
750 "realtime-priority",
751 "Scheduler priority when running in realtime mode.",
753 JackParamInt,
754 &server_ptr->realtime_priority,
755 &server_ptr->default_realtime_priority,
756 value,
757 get_realtime_priority_constraint()) == NULL)
759 goto fail_free_parameters;
762 value.b = false;
763 if (jackctl_add_parameter(
764 &server_ptr->parameters,
765 "temporary",
766 "Exit once all clients have closed their connections.",
768 JackParamBool,
769 &server_ptr->temporary,
770 &server_ptr->default_temporary,
771 value) == NULL)
773 goto fail_free_parameters;
776 value.b = false;
777 if (jackctl_add_parameter(
778 &server_ptr->parameters,
779 "verbose",
780 "Verbose mode.",
782 JackParamBool,
783 &server_ptr->verbose,
784 &server_ptr->default_verbose,
785 value) == NULL)
787 goto fail_free_parameters;
790 value.i = 0;
791 if (jackctl_add_parameter(
792 &server_ptr->parameters,
793 "client-timeout",
794 "Client timeout limit in milliseconds.",
796 JackParamInt,
797 &server_ptr->client_timeout,
798 &server_ptr->default_client_timeout,
799 value) == NULL)
801 goto fail_free_parameters;
804 value.ui = 0;
805 if (jackctl_add_parameter(
806 &server_ptr->parameters,
807 "clock-source",
808 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
810 JackParamUInt,
811 &server_ptr->clock_source,
812 &server_ptr->default_clock_source,
813 value) == NULL)
815 goto fail_free_parameters;
818 value.ui = PORT_NUM;
819 if (jackctl_add_parameter(
820 &server_ptr->parameters,
821 "port-max",
822 "Maximum number of ports.",
824 JackParamUInt,
825 &server_ptr->port_max,
826 &server_ptr->default_port_max,
827 value) == NULL)
829 goto fail_free_parameters;
832 value.b = false;
833 if (jackctl_add_parameter(
834 &server_ptr->parameters,
835 "replace-registry",
836 "Replace shared memory registry.",
838 JackParamBool,
839 &server_ptr->replace_registry,
840 &server_ptr->default_replace_registry,
841 value) == NULL)
843 goto fail_free_parameters;
846 value.b = false;
847 if (jackctl_add_parameter(
848 &server_ptr->parameters,
849 "sync",
850 "Use server synchronous mode.",
852 JackParamBool,
853 &server_ptr->sync,
854 &server_ptr->default_sync,
855 value) == NULL)
857 goto fail_free_parameters;
860 JackServerGlobals::on_device_acquire = on_device_acquire;
861 JackServerGlobals::on_device_release = on_device_release;
863 if (!jackctl_drivers_load(server_ptr))
865 goto fail_free_parameters;
868 /* Allowed to fail */
869 jackctl_internals_load(server_ptr);
871 return server_ptr;
873 fail_free_parameters:
874 jackctl_server_free_parameters(server_ptr);
876 free(server_ptr);
878 fail:
879 return NULL;
882 SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
884 if (server_ptr) {
885 jackctl_server_free_drivers(server_ptr);
886 jackctl_server_free_internals(server_ptr);
887 jackctl_server_free_parameters(server_ptr);
888 free(server_ptr);
892 SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
894 return (server_ptr) ? server_ptr->drivers : NULL;
897 SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
899 if (server_ptr) {
900 server_ptr->engine->Stop();
901 return true;
902 } else {
903 return false;
907 SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
909 if (server_ptr) {
910 server_ptr->engine->Close();
911 delete server_ptr->engine;
913 /* clean up shared memory and files from this server instance */
914 jack_log("cleaning up shared memory");
916 jack_cleanup_shm();
918 jack_log("cleaning up files");
920 JackTools::CleanupFiles(server_ptr->name.str);
922 jack_log("unregistering server `%s'", server_ptr->name.str);
924 jack_unregister_server(server_ptr->name.str);
926 server_ptr->engine = NULL;
928 return true;
929 } else {
930 return false;
934 SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
936 return (server_ptr) ? server_ptr->parameters : NULL;
939 SERVER_EXPORT bool
940 jackctl_server_open(
941 jackctl_server *server_ptr,
942 jackctl_driver *driver_ptr)
944 JSList * paramlist = NULL;
946 try {
948 if (!server_ptr || !driver_ptr) {
949 return false;
952 int rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
953 switch (rc)
955 case EEXIST:
956 jack_error("`%s' server already active", server_ptr->name.str);
957 goto fail;
958 case ENOSPC:
959 jack_error("too many servers already active");
960 goto fail;
961 case ENOMEM:
962 jack_error("no access to shm registry");
963 goto fail;
966 jack_log("server `%s' registered", server_ptr->name.str);
968 /* clean up shared memory and files from any previous
969 * instance of this server name */
970 jack_cleanup_shm();
971 JackTools::CleanupFiles(server_ptr->name.str);
973 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) {
974 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
977 /* check port max value before allocating server */
978 if (server_ptr->port_max.ui > PORT_NUM_MAX) {
979 jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX);
980 goto fail;
983 /* get the engine/driver started */
984 server_ptr->engine = new JackServer(
985 server_ptr->sync.b,
986 server_ptr->temporary.b,
987 server_ptr->client_timeout.i,
988 server_ptr->realtime.b,
989 server_ptr->realtime_priority.i,
990 server_ptr->port_max.ui,
991 server_ptr->verbose.b,
992 (jack_timer_type_t)server_ptr->clock_source.ui,
993 server_ptr->name.str);
994 if (server_ptr->engine == NULL)
996 jack_error("Failed to create new JackServer object");
997 goto fail_unregister;
1000 paramlist = jackctl_create_param_list(driver_ptr->parameters);
1001 if (paramlist == NULL) goto fail_delete;
1002 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, paramlist);
1003 jackctl_destroy_param_list(paramlist);
1004 if (rc < 0)
1006 jack_error("JackServer::Open() failed with %d", rc);
1007 goto fail_delete;
1010 return true;
1012 } catch (std::exception e) {
1013 jack_error("jackctl_server_open error...");
1014 jackctl_destroy_param_list(paramlist);
1017 fail_delete:
1018 delete server_ptr->engine;
1019 server_ptr->engine = NULL;
1021 fail_unregister:
1022 jack_log("cleaning up shared memory");
1024 jack_cleanup_shm();
1026 jack_log("cleaning up files");
1028 JackTools::CleanupFiles(server_ptr->name.str);
1030 jack_log("unregistering server `%s'", server_ptr->name.str);
1032 jack_unregister_server(server_ptr->name.str);
1034 fail:
1035 return false;
1038 SERVER_EXPORT bool
1039 jackctl_server_start(
1040 jackctl_server *server_ptr)
1042 if (!server_ptr) {
1043 return false;
1044 } else {
1045 int rc = server_ptr->engine->Start();
1046 bool result = rc >= 0;
1047 if (! result)
1049 jack_error("JackServer::Start() failed with %d", rc);
1051 return result;
1055 SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
1057 return (driver_ptr) ? driver_ptr->desc_ptr->name : NULL;
1060 SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr)
1062 return (driver_ptr) ? (jackctl_driver_type_t)driver_ptr->desc_ptr->type : (jackctl_driver_type_t)0;
1065 SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
1067 return (driver_ptr) ? driver_ptr->parameters : NULL;
1070 SERVER_EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
1072 return (driver_ptr) ? driver_ptr->desc_ptr : NULL;
1075 SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
1077 return (parameter_ptr) ? parameter_ptr->name : NULL;
1080 SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
1082 return (parameter_ptr) ? parameter_ptr->short_description : NULL;
1085 SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
1087 return (parameter_ptr) ? parameter_ptr->long_description : NULL;
1090 SERVER_EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
1092 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0) : false;
1095 SERVER_EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
1097 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0): false;
1100 SERVER_EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
1102 if (!parameter_ptr) {
1103 return NULL;
1106 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
1108 return 0;
1111 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
1114 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
1116 jack_driver_param_value_t * value_ptr;
1117 union jackctl_parameter_value jackctl_value;
1119 if (!parameter_ptr) {
1120 memset(&jackctl_value, 0, sizeof(jackctl_value));
1121 return jackctl_value;
1124 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1126 switch (parameter_ptr->type)
1128 case JackParamInt:
1129 jackctl_value.i = value_ptr->i;
1130 break;
1131 case JackParamUInt:
1132 jackctl_value.ui = value_ptr->ui;
1133 break;
1134 case JackParamChar:
1135 jackctl_value.c = value_ptr->c;
1136 break;
1137 case JackParamString:
1138 strcpy(jackctl_value.str, value_ptr->str);
1139 break;
1140 default:
1141 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1142 assert(0);
1145 return jackctl_value;
1148 SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1150 return (parameter_ptr) ? parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc : NULL;
1153 SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1155 if (!parameter_ptr || !min_ptr || !max_ptr) {
1156 return;
1159 switch (parameter_ptr->type)
1161 case JackParamInt:
1162 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1163 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1164 return;
1165 case JackParamUInt:
1166 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1167 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1168 return;
1169 default:
1170 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1171 assert(0);
1175 SERVER_EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1177 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0) : false;
1180 SERVER_EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1182 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0) : false;
1185 SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1187 return (parameter_ptr) ? parameter_ptr->type : (jackctl_param_type_t)0;
1190 SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1192 return (parameter_ptr) ? parameter_ptr->id : 0;
1195 SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1197 return (parameter_ptr) ? parameter_ptr->is_set : false;
1200 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1202 if (parameter_ptr) {
1203 return *parameter_ptr->value_ptr;
1204 } else {
1205 union jackctl_parameter_value jackctl_value;
1206 memset(&jackctl_value, 0, sizeof(jackctl_value));
1207 return jackctl_value;
1211 SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1213 if (!parameter_ptr) {
1214 return NULL;
1217 if (!parameter_ptr->is_set)
1219 return true;
1222 parameter_ptr->is_set = false;
1224 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1226 return true;
1229 SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1231 if (!parameter_ptr || !value_ptr) {
1232 return NULL;
1235 parameter_ptr->is_set = true;
1236 *parameter_ptr->value_ptr = *value_ptr;
1238 return true;
1241 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1243 if (parameter_ptr) {
1244 return *parameter_ptr->default_value_ptr;
1245 } else {
1246 union jackctl_parameter_value jackctl_value;
1247 memset(&jackctl_value, 0, sizeof(jackctl_value));
1248 return jackctl_value;
1252 // Internals clients
1254 SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1256 return (server_ptr) ? server_ptr->internals : NULL;
1259 SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1261 return (internal_ptr) ? internal_ptr->desc_ptr->name : NULL;
1264 SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1266 return (internal_ptr) ? internal_ptr->parameters : NULL;
1269 SERVER_EXPORT bool jackctl_server_load_internal(
1270 jackctl_server * server_ptr,
1271 jackctl_internal * internal)
1273 if (!server_ptr || !internal) {
1274 return false;
1277 int status;
1278 if (server_ptr->engine != NULL) {
1279 JSList * paramlist = jackctl_create_param_list(internal->parameters);
1280 if (paramlist == NULL) return false;
1281 server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, paramlist, JackNullOption, &internal->refnum, -1, &status);
1282 jackctl_destroy_param_list(paramlist);
1283 return (internal->refnum > 0);
1284 } else {
1285 return false;
1289 SERVER_EXPORT bool jackctl_server_unload_internal(
1290 jackctl_server * server_ptr,
1291 jackctl_internal * internal)
1293 if (!server_ptr || !internal) {
1294 return false;
1297 int status;
1298 if (server_ptr->engine != NULL && internal->refnum > 0) {
1299 // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
1300 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1301 } else {
1302 return false;
1306 SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1308 if (server_ptr && server_ptr->engine) {
1309 if (server_ptr->engine->IsRunning()) {
1310 jack_error("cannot add a slave in a running server");
1311 return false;
1312 } else {
1313 JSList * paramlist = jackctl_create_param_list(driver_ptr->parameters);
1314 if (paramlist == NULL) return false;
1315 JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, paramlist);
1316 jackctl_destroy_param_list(paramlist);
1317 if (info) {
1318 driver_ptr->infos = jack_slist_append(driver_ptr->infos, info);
1319 return true;
1320 } else {
1321 return false;
1324 } else {
1325 return false;
1329 SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1331 if (server_ptr && server_ptr->engine) {
1332 if (server_ptr->engine->IsRunning()) {
1333 jack_error("cannot remove a slave from a running server");
1334 return false;
1335 } else {
1336 if (driver_ptr->infos) {
1337 JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data;
1338 assert(info);
1339 driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info);
1340 server_ptr->engine->RemoveSlave(info);
1341 delete info;
1342 return true;
1343 } else {
1344 return false;
1347 } else {
1348 return false;
1352 SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1354 if (server_ptr && server_ptr->engine) {
1355 JSList * paramlist = jackctl_create_param_list(driver_ptr->parameters);
1356 if (paramlist == NULL) return false;
1357 jackctl_destroy_param_list(paramlist);
1358 bool ret = (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, paramlist) == 0);
1359 jackctl_destroy_param_list(paramlist);
1360 return ret;
1361 } else {
1362 return false;