Merge branch 'master' into param-order
[jack2.git] / common / JackControlAPI.cpp
bloba2e94fe820d698581151bf62e4bf15fc50a8caae
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 struct jackctl_sigmask
511 HANDLE wait_event;
514 static jackctl_sigmask sigmask;
516 static void signal_handler(int signum)
518 printf("Jack main caught signal %d\n", signum);
519 (void) signal(SIGINT, SIG_DFL);
520 SetEvent(sigmask.wait_event);
523 jackctl_sigmask_t *
524 jackctl_setup_signals(
525 unsigned int flags)
527 if ((sigmask.wait_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
528 jack_error("CreateEvent fails err = %ld", GetLastError());
529 return 0;
532 (void) signal(SIGINT, signal_handler);
533 (void) signal(SIGABRT, signal_handler);
534 (void) signal(SIGTERM, signal_handler);
536 return &sigmask;
539 void jackctl_wait_signals(jackctl_sigmask_t * signals)
541 if (WaitForSingleObject(signals->wait_event, INFINITE) != WAIT_OBJECT_0) {
542 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
546 #else
548 struct jackctl_sigmask
550 sigset_t signals;
553 static jackctl_sigmask sigmask;
555 static
556 void
557 signal_handler(int sig)
559 /* this is used by the child (active) process, but it never
560 gets called unless we are already shutting down after
561 another signal.
563 char buf[64];
564 snprintf(buf, sizeof(buf), "Received signal %d during shutdown (ignored)\n", sig);
567 SERVER_EXPORT jackctl_sigmask_t *
568 jackctl_setup_signals(
569 unsigned int flags)
571 sigset_t allsignals;
572 struct sigaction action;
573 int i;
575 /* ensure that we are in our own process group so that
576 kill (SIG, -pgrp) does the right thing.
579 setsid();
581 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
583 /* what's this for?
585 POSIX says that signals are delivered like this:
587 * if a thread has blocked that signal, it is not
588 a candidate to receive the signal.
589 * of all threads not blocking the signal, pick
590 one at random, and deliver the signal.
592 this means that a simple-minded multi-threaded program can
593 expect to get POSIX signals delivered randomly to any one
594 of its threads,
596 here, we block all signals that we think we might receive
597 and want to catch. all "child" threads will inherit this
598 setting. if we create a thread that calls sigwait() on the
599 same set of signals, implicitly unblocking all those
600 signals. any of those signals that are delivered to the
601 process will be delivered to that thread, and that thread
602 alone. this makes cleanup for a signal-driven exit much
603 easier, since we know which thread is doing it and more
604 importantly, we are free to call async-unsafe functions,
605 because the code is executing in normal thread context
606 after a return from sigwait().
609 sigemptyset(&sigmask.signals);
610 sigaddset(&sigmask.signals, SIGHUP);
611 sigaddset(&sigmask.signals, SIGINT);
612 sigaddset(&sigmask.signals, SIGQUIT);
613 sigaddset(&sigmask.signals, SIGPIPE);
614 sigaddset(&sigmask.signals, SIGTERM);
615 sigaddset(&sigmask.signals, SIGUSR1);
616 sigaddset(&sigmask.signals, SIGUSR2);
618 /* all child threads will inherit this mask unless they
619 * explicitly reset it
622 pthread_sigmask(SIG_BLOCK, &sigmask.signals, 0);
624 /* install a do-nothing handler because otherwise pthreads
625 behaviour is undefined when we enter sigwait.
628 sigfillset(&allsignals);
629 action.sa_handler = signal_handler;
630 action.sa_mask = allsignals;
631 action.sa_flags = SA_RESTART|SA_RESETHAND;
633 for (i = 1; i < NSIG; i++)
635 if (sigismember (&sigmask.signals, i))
637 sigaction(i, &action, 0);
641 return &sigmask;
644 SERVER_EXPORT void
645 jackctl_wait_signals(jackctl_sigmask_t * sigmask)
647 int sig;
648 bool waiting = true;
650 while (waiting) {
651 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
652 sigwait(&sigmask->signals);
653 #else
654 sigwait(&sigmask->signals, &sig);
655 #endif
656 fprintf(stderr, "Jack main caught signal %d\n", sig);
658 switch (sig) {
659 case SIGUSR1:
660 //jack_dump_configuration(engine, 1);
661 break;
662 case SIGUSR2:
663 // driver exit
664 waiting = false;
665 break;
666 case SIGTTOU:
667 break;
668 default:
669 waiting = false;
670 break;
674 if (sig != SIGSEGV) {
675 // unblock signals so we can see them during shutdown.
676 // this will help prod developers not to lose sight of
677 // bugs that cause segfaults etc. during shutdown.
678 sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0);
681 #endif
683 static
684 jack_driver_param_constraint_desc_t *
685 get_realtime_priority_constraint()
687 jack_driver_param_constraint_desc_t * constraint_ptr;
688 int min, max;
690 if (!jack_get_thread_realtime_priority_range(&min, &max))
692 return NULL;
695 //jack_info("realtime priority range is (%d,%d)", min, max);
697 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
698 if (constraint_ptr == NULL)
700 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
701 return NULL;
703 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
705 constraint_ptr->constraint.range.min.i = min;
706 constraint_ptr->constraint.range.max.i = max;
708 return constraint_ptr;
711 SERVER_EXPORT jackctl_server_t * jackctl_server_create(
712 bool (* on_device_acquire)(const char * device_name),
713 void (* on_device_release)(const char * device_name))
715 struct jackctl_server * server_ptr;
716 union jackctl_parameter_value value;
718 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
719 if (server_ptr == NULL)
721 jack_error("Cannot allocate memory for jackctl_server structure.");
722 goto fail;
725 server_ptr->drivers = NULL;
726 server_ptr->internals = NULL;
727 server_ptr->parameters = NULL;
728 server_ptr->engine = NULL;
730 strcpy(value.str, JACK_DEFAULT_SERVER_NAME);
731 if (jackctl_add_parameter(
732 &server_ptr->parameters,
733 "name",
734 "Server name to use.",
736 JackParamString,
737 &server_ptr->name,
738 &server_ptr->default_name,
739 value) == NULL)
741 goto fail_free_parameters;
744 value.b = true;
745 if (jackctl_add_parameter(
746 &server_ptr->parameters,
747 "realtime",
748 "Whether to use realtime mode.",
749 "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.",
750 JackParamBool,
751 &server_ptr->realtime,
752 &server_ptr->default_realtime,
753 value) == NULL)
755 goto fail_free_parameters;
758 value.i = 10;
759 if (jackctl_add_parameter(
760 &server_ptr->parameters,
761 "realtime-priority",
762 "Scheduler priority when running in realtime mode.",
764 JackParamInt,
765 &server_ptr->realtime_priority,
766 &server_ptr->default_realtime_priority,
767 value,
768 get_realtime_priority_constraint()) == NULL)
770 goto fail_free_parameters;
773 value.b = false;
774 if (jackctl_add_parameter(
775 &server_ptr->parameters,
776 "temporary",
777 "Exit once all clients have closed their connections.",
779 JackParamBool,
780 &server_ptr->temporary,
781 &server_ptr->default_temporary,
782 value) == NULL)
784 goto fail_free_parameters;
787 value.b = false;
788 if (jackctl_add_parameter(
789 &server_ptr->parameters,
790 "verbose",
791 "Verbose mode.",
793 JackParamBool,
794 &server_ptr->verbose,
795 &server_ptr->default_verbose,
796 value) == NULL)
798 goto fail_free_parameters;
801 value.i = 0;
802 if (jackctl_add_parameter(
803 &server_ptr->parameters,
804 "client-timeout",
805 "Client timeout limit in milliseconds.",
807 JackParamInt,
808 &server_ptr->client_timeout,
809 &server_ptr->default_client_timeout,
810 value) == NULL)
812 goto fail_free_parameters;
815 value.ui = 0;
816 if (jackctl_add_parameter(
817 &server_ptr->parameters,
818 "clock-source",
819 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
821 JackParamUInt,
822 &server_ptr->clock_source,
823 &server_ptr->default_clock_source,
824 value) == NULL)
826 goto fail_free_parameters;
829 value.ui = PORT_NUM;
830 if (jackctl_add_parameter(
831 &server_ptr->parameters,
832 "port-max",
833 "Maximum number of ports.",
835 JackParamUInt,
836 &server_ptr->port_max,
837 &server_ptr->default_port_max,
838 value) == NULL)
840 goto fail_free_parameters;
843 value.b = false;
844 if (jackctl_add_parameter(
845 &server_ptr->parameters,
846 "replace-registry",
847 "Replace shared memory registry.",
849 JackParamBool,
850 &server_ptr->replace_registry,
851 &server_ptr->default_replace_registry,
852 value) == NULL)
854 goto fail_free_parameters;
857 value.b = false;
858 if (jackctl_add_parameter(
859 &server_ptr->parameters,
860 "sync",
861 "Use server synchronous mode.",
863 JackParamBool,
864 &server_ptr->sync,
865 &server_ptr->default_sync,
866 value) == NULL)
868 goto fail_free_parameters;
871 JackServerGlobals::on_device_acquire = on_device_acquire;
872 JackServerGlobals::on_device_release = on_device_release;
874 if (!jackctl_drivers_load(server_ptr))
876 goto fail_free_parameters;
879 /* Allowed to fail */
880 jackctl_internals_load(server_ptr);
882 return server_ptr;
884 fail_free_parameters:
885 jackctl_server_free_parameters(server_ptr);
887 free(server_ptr);
889 fail:
890 return NULL;
893 SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
895 if (server_ptr) {
896 jackctl_server_free_drivers(server_ptr);
897 jackctl_server_free_internals(server_ptr);
898 jackctl_server_free_parameters(server_ptr);
899 free(server_ptr);
903 SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
905 return (server_ptr) ? server_ptr->drivers : NULL;
908 SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
910 if (server_ptr) {
911 server_ptr->engine->Stop();
912 return true;
913 } else {
914 return false;
918 SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
920 if (server_ptr) {
921 server_ptr->engine->Close();
922 delete server_ptr->engine;
924 /* clean up shared memory and files from this server instance */
925 jack_log("Cleaning up shared memory");
927 jack_cleanup_shm();
929 jack_log("Cleaning up files");
931 JackTools::CleanupFiles(server_ptr->name.str);
933 jack_log("Unregistering server `%s'", server_ptr->name.str);
935 jack_unregister_server(server_ptr->name.str);
937 server_ptr->engine = NULL;
939 return true;
940 } else {
941 return false;
945 SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
947 return (server_ptr) ? server_ptr->parameters : NULL;
950 SERVER_EXPORT bool
951 jackctl_server_open(
952 jackctl_server *server_ptr,
953 jackctl_driver *driver_ptr)
955 JSList * paramlist = NULL;
957 try {
959 if (!server_ptr || !driver_ptr) {
960 return false;
963 int rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
964 switch (rc)
966 case EEXIST:
967 jack_error("`%s' server already active", server_ptr->name.str);
968 goto fail;
969 case ENOSPC:
970 jack_error("Too many servers already active");
971 goto fail;
972 case ENOMEM:
973 jack_error("No access to shm registry");
974 goto fail;
977 jack_log("Server `%s' registered", server_ptr->name.str);
979 /* clean up shared memory and files from any previous
980 * instance of this server name */
981 jack_cleanup_shm();
982 JackTools::CleanupFiles(server_ptr->name.str);
984 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) {
985 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
988 /* check port max value before allocating server */
989 if (server_ptr->port_max.ui > PORT_NUM_MAX) {
990 jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX);
991 goto fail;
994 /* get the engine/driver started */
995 server_ptr->engine = new JackServer(
996 server_ptr->sync.b,
997 server_ptr->temporary.b,
998 server_ptr->client_timeout.i,
999 server_ptr->realtime.b,
1000 server_ptr->realtime_priority.i,
1001 server_ptr->port_max.ui,
1002 server_ptr->verbose.b,
1003 (jack_timer_type_t)server_ptr->clock_source.ui,
1004 server_ptr->name.str);
1005 if (server_ptr->engine == NULL)
1007 jack_error("Failed to create new JackServer object");
1008 goto fail_unregister;
1011 paramlist = jackctl_create_param_list(driver_ptr->parameters);
1012 if (paramlist == NULL) goto fail_delete;
1013 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, paramlist);
1014 jackctl_destroy_param_list(paramlist);
1015 if (rc < 0)
1017 jack_error("JackServer::Open failed with %d", rc);
1018 goto fail_delete;
1021 return true;
1023 } catch (std::exception e) {
1024 jack_error("jackctl_server_open error...");
1025 jackctl_destroy_param_list(paramlist);
1028 fail_delete:
1029 delete server_ptr->engine;
1030 server_ptr->engine = NULL;
1032 fail_unregister:
1033 jack_log("Cleaning up shared memory");
1035 jack_cleanup_shm();
1037 jack_log("Cleaning up files");
1039 JackTools::CleanupFiles(server_ptr->name.str);
1041 jack_log("Unregistering server `%s'", server_ptr->name.str);
1043 jack_unregister_server(server_ptr->name.str);
1045 fail:
1046 return false;
1049 SERVER_EXPORT bool
1050 jackctl_server_start(
1051 jackctl_server *server_ptr)
1053 if (!server_ptr) {
1054 return false;
1055 } else {
1056 int rc = server_ptr->engine->Start();
1057 bool result = rc >= 0;
1058 if (! result)
1060 jack_error("JackServer::Start() failed with %d", rc);
1062 return result;
1066 SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
1068 return (driver_ptr) ? driver_ptr->desc_ptr->name : NULL;
1071 SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr)
1073 return (driver_ptr) ? (jackctl_driver_type_t)driver_ptr->desc_ptr->type : (jackctl_driver_type_t)0;
1076 SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
1078 return (driver_ptr) ? driver_ptr->parameters : NULL;
1081 SERVER_EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
1083 return (driver_ptr) ? driver_ptr->desc_ptr : NULL;
1086 SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
1088 return (parameter_ptr) ? parameter_ptr->name : NULL;
1091 SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
1093 return (parameter_ptr) ? parameter_ptr->short_description : NULL;
1096 SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
1098 return (parameter_ptr) ? parameter_ptr->long_description : NULL;
1101 SERVER_EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
1103 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0) : false;
1106 SERVER_EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
1108 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0): false;
1111 SERVER_EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
1113 if (!parameter_ptr) {
1114 return NULL;
1117 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
1119 return 0;
1122 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
1125 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
1127 jack_driver_param_value_t * value_ptr;
1128 union jackctl_parameter_value jackctl_value;
1130 if (!parameter_ptr) {
1131 memset(&jackctl_value, 0, sizeof(jackctl_value));
1132 return jackctl_value;
1135 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1137 switch (parameter_ptr->type)
1139 case JackParamInt:
1140 jackctl_value.i = value_ptr->i;
1141 break;
1142 case JackParamUInt:
1143 jackctl_value.ui = value_ptr->ui;
1144 break;
1145 case JackParamChar:
1146 jackctl_value.c = value_ptr->c;
1147 break;
1148 case JackParamString:
1149 strcpy(jackctl_value.str, value_ptr->str);
1150 break;
1151 default:
1152 jack_error("Bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1153 assert(0);
1156 return jackctl_value;
1159 SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1161 return (parameter_ptr) ? parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc : NULL;
1164 SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1166 if (!parameter_ptr || !min_ptr || !max_ptr) {
1167 return;
1170 switch (parameter_ptr->type)
1172 case JackParamInt:
1173 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1174 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1175 return;
1176 case JackParamUInt:
1177 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1178 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1179 return;
1180 default:
1181 jack_error("Bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1182 assert(0);
1186 SERVER_EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1188 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0) : false;
1191 SERVER_EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1193 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0) : false;
1196 SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1198 return (parameter_ptr) ? parameter_ptr->type : (jackctl_param_type_t)0;
1201 SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1203 return (parameter_ptr) ? parameter_ptr->id : 0;
1206 SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1208 return (parameter_ptr) ? parameter_ptr->is_set : false;
1211 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1213 if (parameter_ptr) {
1214 return *parameter_ptr->value_ptr;
1215 } else {
1216 union jackctl_parameter_value jackctl_value;
1217 memset(&jackctl_value, 0, sizeof(jackctl_value));
1218 return jackctl_value;
1222 SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1224 if (!parameter_ptr) {
1225 return NULL;
1228 if (!parameter_ptr->is_set)
1230 return true;
1233 parameter_ptr->is_set = false;
1235 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1237 return true;
1240 SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1242 if (!parameter_ptr || !value_ptr) {
1243 return NULL;
1246 parameter_ptr->is_set = true;
1247 *parameter_ptr->value_ptr = *value_ptr;
1249 return true;
1252 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1254 if (parameter_ptr) {
1255 return *parameter_ptr->default_value_ptr;
1256 } else {
1257 union jackctl_parameter_value jackctl_value;
1258 memset(&jackctl_value, 0, sizeof(jackctl_value));
1259 return jackctl_value;
1263 // Internals clients
1265 SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1267 return (server_ptr) ? server_ptr->internals : NULL;
1270 SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1272 return (internal_ptr) ? internal_ptr->desc_ptr->name : NULL;
1275 SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1277 return (internal_ptr) ? internal_ptr->parameters : NULL;
1280 SERVER_EXPORT bool jackctl_server_load_internal(
1281 jackctl_server * server_ptr,
1282 jackctl_internal * internal)
1284 if (!server_ptr || !internal) {
1285 return false;
1288 int status;
1289 if (server_ptr->engine != NULL) {
1290 JSList * paramlist = jackctl_create_param_list(internal->parameters);
1291 if (paramlist == NULL) return false;
1292 server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, paramlist, JackNullOption, &internal->refnum, -1, &status);
1293 jackctl_destroy_param_list(paramlist);
1294 return (internal->refnum > 0);
1295 } else {
1296 return false;
1300 SERVER_EXPORT bool jackctl_server_unload_internal(
1301 jackctl_server * server_ptr,
1302 jackctl_internal * internal)
1304 if (!server_ptr || !internal) {
1305 return false;
1308 int status;
1309 if (server_ptr->engine != NULL && internal->refnum > 0) {
1310 // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
1311 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1312 } else {
1313 return false;
1317 SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1319 if (server_ptr && server_ptr->engine) {
1320 if (server_ptr->engine->IsRunning()) {
1321 jack_error("Cannot add a slave in a running server");
1322 return false;
1323 } else {
1324 JSList * paramlist = jackctl_create_param_list(driver_ptr->parameters);
1325 if (paramlist == NULL) return false;
1326 JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, paramlist);
1327 jackctl_destroy_param_list(paramlist);
1328 if (info) {
1329 driver_ptr->infos = jack_slist_append(driver_ptr->infos, info);
1330 return true;
1331 } else {
1332 return false;
1335 } else {
1336 return false;
1340 SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1342 if (server_ptr && server_ptr->engine) {
1343 if (server_ptr->engine->IsRunning()) {
1344 jack_error("Cannot remove a slave from a running server");
1345 return false;
1346 } else {
1347 if (driver_ptr->infos) {
1348 JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data;
1349 assert(info);
1350 driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info);
1351 server_ptr->engine->RemoveSlave(info);
1352 delete info;
1353 return true;
1354 } else {
1355 return false;
1358 } else {
1359 return false;
1363 SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1365 if (server_ptr && server_ptr->engine) {
1366 JSList * paramlist = jackctl_create_param_list(driver_ptr->parameters);
1367 if (paramlist == NULL) return false;
1368 jackctl_destroy_param_list(paramlist);
1369 bool ret = (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, paramlist) == 0);
1370 jackctl_destroy_param_list(paramlist);
1371 return ret;
1372 } else {
1373 return false;