Rename system_midi:* back to system:midi_*
[jack2.git] / common / JackControlAPI.cpp
blob11abb4e6d73cf054c4400dd3c6f53b6d769e78e4
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 /* JackEngine::CheckPortsConnect() has some assumptions about char values */
51 static struct jack_constraint_enum_char_descriptor self_connect_mode_constraint_descr_array[] =
53 { ' ', "Don't restrict self connect requests" },
54 { 'E', "Fail self connect requests to external ports only" },
55 { 'e', "Ignore self connect requests to external ports only" },
56 { 'A', "Fail all self connect requests" },
57 { 'a', "Ignore all self connect requests" },
58 { 0 }
61 struct jackctl_server
63 JSList * drivers;
64 JSList * internals;
65 JSList * parameters;
67 class JackServer * engine;
69 /* string, server name */
70 union jackctl_parameter_value name;
71 union jackctl_parameter_value default_name;
73 /* bool, whether to be "realtime" */
74 union jackctl_parameter_value realtime;
75 union jackctl_parameter_value default_realtime;
77 /* int32_t */
78 union jackctl_parameter_value realtime_priority;
79 union jackctl_parameter_value default_realtime_priority;
81 /* bool, whether to exit once all clients have closed their connections */
82 union jackctl_parameter_value temporary;
83 union jackctl_parameter_value default_temporary;
85 /* bool, whether to be verbose */
86 union jackctl_parameter_value verbose;
87 union jackctl_parameter_value default_verbose;
89 /* int32_t, msecs; if zero, use period size. */
90 union jackctl_parameter_value client_timeout;
91 union jackctl_parameter_value default_client_timeout;
93 /* uint32_t, clock source type */
94 union jackctl_parameter_value clock_source;
95 union jackctl_parameter_value default_clock_source;
97 /* uint32_t, max port number */
98 union jackctl_parameter_value port_max;
99 union jackctl_parameter_value default_port_max;
101 /* bool */
102 union jackctl_parameter_value replace_registry;
103 union jackctl_parameter_value default_replace_registry;
105 /* bool, synchronous or asynchronous engine mode */
106 union jackctl_parameter_value sync;
107 union jackctl_parameter_value default_sync;
109 /* char enum, self connect mode mode */
110 union jackctl_parameter_value self_connect_mode;
111 union jackctl_parameter_value default_self_connect_mode;
114 struct jackctl_driver
116 jack_driver_desc_t * desc_ptr;
117 JSList * parameters;
118 JSList * infos;
121 struct jackctl_internal
123 jack_driver_desc_t * desc_ptr;
124 JSList * parameters;
125 int refnum;
128 struct jackctl_parameter
130 const char * name;
131 const char * short_description;
132 const char * long_description;
133 jackctl_param_type_t type;
134 bool is_set;
135 union jackctl_parameter_value * value_ptr;
136 union jackctl_parameter_value * default_value_ptr;
138 union jackctl_parameter_value value;
139 union jackctl_parameter_value default_value;
140 struct jackctl_driver * driver_ptr;
141 char id;
142 jack_driver_param_constraint_desc_t * constraint_ptr;
145 const char * jack_get_self_connect_mode_description(char mode)
147 struct jack_constraint_enum_char_descriptor * descr_ptr;
149 for (descr_ptr = self_connect_mode_constraint_descr_array;
150 descr_ptr->value;
151 descr_ptr++)
152 if (descr_ptr->value == mode) return descr_ptr->short_desc;
154 return NULL;
157 static
158 struct jackctl_parameter *
159 jackctl_add_parameter(
160 JSList ** parameters_list_ptr_ptr,
161 const char * name,
162 const char * short_description,
163 const char * long_description,
164 jackctl_param_type_t type,
165 union jackctl_parameter_value * value_ptr,
166 union jackctl_parameter_value * default_value_ptr,
167 union jackctl_parameter_value value,
168 jack_driver_param_constraint_desc_t * constraint_ptr = NULL)
170 struct jackctl_parameter * parameter_ptr;
172 parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter));
173 if (parameter_ptr == NULL)
175 jack_error("Cannot allocate memory for jackctl_parameter structure.");
176 goto fail;
179 parameter_ptr->name = name;
180 parameter_ptr->short_description = short_description;
181 parameter_ptr->long_description = long_description;
182 parameter_ptr->type = type;
183 parameter_ptr->is_set = false;
185 if (value_ptr == NULL)
187 value_ptr = &parameter_ptr->value;
190 if (default_value_ptr == NULL)
192 default_value_ptr = &parameter_ptr->default_value;
195 parameter_ptr->value_ptr = value_ptr;
196 parameter_ptr->default_value_ptr = default_value_ptr;
198 *value_ptr = *default_value_ptr = value;
200 parameter_ptr->driver_ptr = NULL;
201 parameter_ptr->id = 0;
202 parameter_ptr->constraint_ptr = constraint_ptr;
204 *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
206 return parameter_ptr;
208 fail:
209 return NULL;
212 static
213 void
214 jackctl_free_driver_parameters(
215 struct jackctl_driver * driver_ptr)
217 JSList * next_node_ptr;
219 while (driver_ptr->parameters)
221 next_node_ptr = driver_ptr->parameters->next;
222 jack_constraint_free(((jackctl_parameter *)driver_ptr->parameters->data)->constraint_ptr);
223 free(driver_ptr->parameters->data);
224 free(driver_ptr->parameters);
225 driver_ptr->parameters = next_node_ptr;
229 static
230 bool
231 jackctl_add_driver_parameters(
232 struct jackctl_driver * driver_ptr)
234 unsigned int i;
236 union jackctl_parameter_value jackctl_value;
237 jackctl_param_type_t jackctl_type;
238 struct jackctl_parameter * parameter_ptr;
239 jack_driver_param_desc_t * descriptor_ptr;
241 for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
243 descriptor_ptr = driver_ptr->desc_ptr->params + i;
245 switch (descriptor_ptr->type)
247 case JackDriverParamInt:
248 jackctl_type = JackParamInt;
249 jackctl_value.i = descriptor_ptr->value.i;
250 break;
251 case JackDriverParamUInt:
252 jackctl_type = JackParamUInt;
253 jackctl_value.ui = descriptor_ptr->value.ui;
254 break;
255 case JackDriverParamChar:
256 jackctl_type = JackParamChar;
257 jackctl_value.c = descriptor_ptr->value.c;
258 break;
259 case JackDriverParamString:
260 jackctl_type = JackParamString;
261 strcpy(jackctl_value.str, descriptor_ptr->value.str);
262 break;
263 case JackDriverParamBool:
264 jackctl_type = JackParamBool;
265 jackctl_value.b = descriptor_ptr->value.i;
266 break;
267 default:
268 jack_error("Unknown driver parameter type %i", (int)descriptor_ptr->type);
269 assert(0);
270 goto fail;
273 parameter_ptr = jackctl_add_parameter(
274 &driver_ptr->parameters,
275 descriptor_ptr->name,
276 descriptor_ptr->short_desc,
277 descriptor_ptr->long_desc,
278 jackctl_type,
279 NULL,
280 NULL,
281 jackctl_value,
282 descriptor_ptr->constraint);
284 if (parameter_ptr == NULL)
286 goto fail;
289 parameter_ptr->driver_ptr = driver_ptr;
290 parameter_ptr->id = descriptor_ptr->character;
293 return true;
295 fail:
296 jackctl_free_driver_parameters(driver_ptr);
298 return false;
301 /* destroy jack_driver_param_desc_t list created by jackctl_create_param_list() */
302 static void
303 jackctl_destroy_param_list(
304 JSList * params)
306 JSList * next;
308 while (params)
310 next = params->next;
311 free(params->data);
312 free(params);
313 params = next;
317 /* for drivers and internals are configured through jack_driver_param_t JSList */
318 /* this function creates such list from a jackctl_parameter list */
319 static
320 bool
321 jackctl_create_param_list(
322 const JSList * paramlist,
323 JSList ** retparamlist)
325 jackctl_parameter * param_ptr;
326 jack_driver_param_t * retparam_ptr;
328 *retparamlist = NULL;
329 while (paramlist != NULL)
331 param_ptr = (jackctl_parameter *)paramlist->data;
332 if (param_ptr->is_set)
334 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
335 retparam_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t));
336 if (retparam_ptr == NULL)
338 jack_error ("Allocation of jack_driver_param_t structure failed");
339 goto destroy;
342 retparam_ptr->character = param_ptr->id;
344 switch (param_ptr->type)
346 case JackParamInt:
347 retparam_ptr->value.i = param_ptr->value_ptr->i;
348 break;
349 case JackParamUInt:
350 retparam_ptr->value.ui = param_ptr->value_ptr->ui;
351 break;
352 case JackParamChar:
353 retparam_ptr->value.c = param_ptr->value_ptr->c;
354 break;
355 case JackParamString:
356 strcpy(retparam_ptr->value.str, param_ptr->value_ptr->str);
357 break;
358 case JackParamBool:
359 retparam_ptr->value.i = param_ptr->value_ptr->b;
360 break;
361 default:
362 jack_error("Unknown parameter type %i", (int)param_ptr->type);
363 assert(0);
364 goto free;
367 *retparamlist = jack_slist_append(*retparamlist, retparam_ptr);
370 paramlist = paramlist->next;
373 return true;
375 free:
376 free(retparam_ptr);
377 destroy:
378 jackctl_destroy_param_list(*retparamlist);
379 return false;
382 static int
383 jackctl_drivers_load(
384 struct jackctl_server * server_ptr)
386 struct jackctl_driver * driver_ptr;
387 JSList *node_ptr;
388 JSList *descriptor_node_ptr;
390 descriptor_node_ptr = jack_drivers_load(NULL);
391 if (descriptor_node_ptr == NULL)
393 jack_error("Could not find any drivers in driver directory!");
394 return false;
397 while (descriptor_node_ptr != NULL)
399 driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver));
400 if (driver_ptr == NULL)
402 jack_error("Memory allocation of jackctl_driver structure failed.");
403 goto next;
406 driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
407 driver_ptr->parameters = NULL;
408 driver_ptr->infos = NULL;
410 if (!jackctl_add_driver_parameters(driver_ptr))
412 assert(driver_ptr->parameters == NULL);
413 free(driver_ptr);
414 goto next;
417 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
419 next:
420 node_ptr = descriptor_node_ptr;
421 descriptor_node_ptr = descriptor_node_ptr->next;
422 free(node_ptr);
425 return true;
428 static
429 void
430 jackctl_server_free_drivers(
431 struct jackctl_server * server_ptr)
433 JSList * next_node_ptr;
434 struct jackctl_driver * driver_ptr;
436 while (server_ptr->drivers)
438 next_node_ptr = server_ptr->drivers->next;
439 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
441 jackctl_free_driver_parameters(driver_ptr);
442 free(driver_ptr->desc_ptr->params);
443 free(driver_ptr->desc_ptr);
444 free(driver_ptr);
446 free(server_ptr->drivers);
447 server_ptr->drivers = next_node_ptr;
451 static int
452 jackctl_internals_load(
453 struct jackctl_server * server_ptr)
455 struct jackctl_internal * internal_ptr;
456 JSList *node_ptr;
457 JSList *descriptor_node_ptr;
459 descriptor_node_ptr = jack_internals_load(NULL);
460 if (descriptor_node_ptr == NULL)
462 jack_error("Could not find any internals in driver directory!");
463 return false;
466 while (descriptor_node_ptr != NULL)
468 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal));
469 if (internal_ptr == NULL)
471 jack_error("Memory allocation of jackctl_driver structure failed.");
472 goto next;
475 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
476 internal_ptr->parameters = NULL;
477 internal_ptr->refnum = -1;
479 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr))
481 assert(internal_ptr->parameters == NULL);
482 free(internal_ptr);
483 goto next;
486 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr);
488 next:
489 node_ptr = descriptor_node_ptr;
490 descriptor_node_ptr = descriptor_node_ptr->next;
491 free(node_ptr);
494 return true;
497 static
498 void
499 jackctl_server_free_internals(
500 struct jackctl_server * server_ptr)
502 JSList * next_node_ptr;
503 struct jackctl_internal * internal_ptr;
505 while (server_ptr->internals)
507 next_node_ptr = server_ptr->internals->next;
508 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data;
510 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr);
511 free(internal_ptr->desc_ptr->params);
512 free(internal_ptr->desc_ptr);
513 free(internal_ptr);
515 free(server_ptr->internals);
516 server_ptr->internals = next_node_ptr;
520 static
521 void
522 jackctl_server_free_parameters(
523 struct jackctl_server * server_ptr)
525 JSList * next_node_ptr;
527 while (server_ptr->parameters)
529 next_node_ptr = server_ptr->parameters->next;
530 jack_constraint_free(((jackctl_parameter *)server_ptr->parameters->data)->constraint_ptr);
531 free(server_ptr->parameters->data);
532 free(server_ptr->parameters);
533 server_ptr->parameters = next_node_ptr;
537 #ifdef WIN32
539 struct jackctl_sigmask
541 HANDLE wait_event;
544 static jackctl_sigmask sigmask;
546 static void signal_handler(int signum)
548 printf("Jack main caught signal %d\n", signum);
549 (void) signal(SIGINT, SIG_DFL);
550 SetEvent(sigmask.wait_event);
553 jackctl_sigmask_t *
554 jackctl_setup_signals(
555 unsigned int flags)
557 if ((sigmask.wait_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
558 jack_error("CreateEvent fails err = %ld", GetLastError());
559 return 0;
562 (void) signal(SIGINT, signal_handler);
563 (void) signal(SIGABRT, signal_handler);
564 (void) signal(SIGTERM, signal_handler);
566 return &sigmask;
569 void jackctl_wait_signals(jackctl_sigmask_t * signals)
571 if (WaitForSingleObject(signals->wait_event, INFINITE) != WAIT_OBJECT_0) {
572 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
576 #else
578 struct jackctl_sigmask
580 sigset_t signals;
583 static jackctl_sigmask sigmask;
585 static
586 void
587 signal_handler(int sig)
589 /* this is used by the child (active) process, but it never
590 gets called unless we are already shutting down after
591 another signal.
593 char buf[64];
594 snprintf(buf, sizeof(buf), "Received signal %d during shutdown (ignored)\n", sig);
597 SERVER_EXPORT jackctl_sigmask_t *
598 jackctl_setup_signals(
599 unsigned int flags)
601 sigset_t allsignals;
602 struct sigaction action;
603 int i;
605 /* ensure that we are in our own process group so that
606 kill (SIG, -pgrp) does the right thing.
609 setsid();
611 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
613 /* what's this for?
615 POSIX says that signals are delivered like this:
617 * if a thread has blocked that signal, it is not
618 a candidate to receive the signal.
619 * of all threads not blocking the signal, pick
620 one at random, and deliver the signal.
622 this means that a simple-minded multi-threaded program can
623 expect to get POSIX signals delivered randomly to any one
624 of its threads,
626 here, we block all signals that we think we might receive
627 and want to catch. all "child" threads will inherit this
628 setting. if we create a thread that calls sigwait() on the
629 same set of signals, implicitly unblocking all those
630 signals. any of those signals that are delivered to the
631 process will be delivered to that thread, and that thread
632 alone. this makes cleanup for a signal-driven exit much
633 easier, since we know which thread is doing it and more
634 importantly, we are free to call async-unsafe functions,
635 because the code is executing in normal thread context
636 after a return from sigwait().
639 sigemptyset(&sigmask.signals);
640 sigaddset(&sigmask.signals, SIGHUP);
641 sigaddset(&sigmask.signals, SIGINT);
642 sigaddset(&sigmask.signals, SIGQUIT);
643 sigaddset(&sigmask.signals, SIGPIPE);
644 sigaddset(&sigmask.signals, SIGTERM);
645 #ifndef __ANDROID__
646 /* android's bionic c doesn't provide pthread_cancel() and related functions.
647 * to solve this issue, use pthread_kill() & SIGUSR1 instead.
649 sigaddset(&sigmask.signals, SIGUSR1);
650 #endif
651 sigaddset(&sigmask.signals, SIGUSR2);
653 /* all child threads will inherit this mask unless they
654 * explicitly reset it
657 pthread_sigmask(SIG_BLOCK, &sigmask.signals, 0);
659 /* install a do-nothing handler because otherwise pthreads
660 behaviour is undefined when we enter sigwait.
663 sigfillset(&allsignals);
664 action.sa_handler = signal_handler;
665 action.sa_mask = allsignals;
666 action.sa_flags = SA_RESTART|SA_RESETHAND;
668 for (i = 1; i < NSIG; i++)
670 if (sigismember (&sigmask.signals, i))
672 sigaction(i, &action, 0);
676 return &sigmask;
679 SERVER_EXPORT void
680 jackctl_wait_signals(jackctl_sigmask_t * sigmask)
682 int sig;
683 bool waiting = true;
685 while (waiting) {
686 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
687 sigwait(&sigmask->signals);
688 #else
689 sigwait(&sigmask->signals, &sig);
690 #endif
691 fprintf(stderr, "Jack main caught signal %d\n", sig);
693 switch (sig) {
694 case SIGUSR1:
695 //jack_dump_configuration(engine, 1);
696 break;
697 case SIGUSR2:
698 // driver exit
699 waiting = false;
700 break;
701 case SIGTTOU:
702 break;
703 default:
704 waiting = false;
705 break;
709 if (sig != SIGSEGV) {
710 // unblock signals so we can see them during shutdown.
711 // this will help prod developers not to lose sight of
712 // bugs that cause segfaults etc. during shutdown.
713 sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0);
716 #endif
718 static
719 jack_driver_param_constraint_desc_t *
720 get_realtime_priority_constraint()
722 jack_driver_param_constraint_desc_t * constraint_ptr;
723 int min, max;
725 if (!jack_get_thread_realtime_priority_range(&min, &max))
727 return NULL;
730 //jack_info("realtime priority range is (%d,%d)", min, max);
732 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_constraint_desc_t));
733 if (constraint_ptr == NULL)
735 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
736 return NULL;
738 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
740 constraint_ptr->constraint.range.min.i = min;
741 constraint_ptr->constraint.range.max.i = max;
743 return constraint_ptr;
746 SERVER_EXPORT jackctl_server_t * jackctl_server_create(
747 bool (* on_device_acquire)(const char * device_name),
748 void (* on_device_release)(const char * device_name))
750 struct jackctl_server * server_ptr;
751 union jackctl_parameter_value value;
753 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
754 if (server_ptr == NULL)
756 jack_error("Cannot allocate memory for jackctl_server structure.");
757 goto fail;
760 server_ptr->drivers = NULL;
761 server_ptr->internals = NULL;
762 server_ptr->parameters = NULL;
763 server_ptr->engine = NULL;
765 strcpy(value.str, JackTools::DefaultServerName());
766 if (jackctl_add_parameter(
767 &server_ptr->parameters,
768 "name",
769 "Server name to use.",
771 JackParamString,
772 &server_ptr->name,
773 &server_ptr->default_name,
774 value) == NULL)
776 goto fail_free_parameters;
779 value.b = true;
780 if (jackctl_add_parameter(
781 &server_ptr->parameters,
782 "realtime",
783 "Whether to use realtime mode.",
784 "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.",
785 JackParamBool,
786 &server_ptr->realtime,
787 &server_ptr->default_realtime,
788 value) == NULL)
790 goto fail_free_parameters;
793 value.i = 10;
794 if (jackctl_add_parameter(
795 &server_ptr->parameters,
796 "realtime-priority",
797 "Scheduler priority when running in realtime mode.",
799 JackParamInt,
800 &server_ptr->realtime_priority,
801 &server_ptr->default_realtime_priority,
802 value,
803 get_realtime_priority_constraint()) == NULL)
805 goto fail_free_parameters;
808 value.b = false;
809 if (jackctl_add_parameter(
810 &server_ptr->parameters,
811 "temporary",
812 "Exit once all clients have closed their connections.",
814 JackParamBool,
815 &server_ptr->temporary,
816 &server_ptr->default_temporary,
817 value) == NULL)
819 goto fail_free_parameters;
822 value.b = false;
823 if (jackctl_add_parameter(
824 &server_ptr->parameters,
825 "verbose",
826 "Verbose mode.",
828 JackParamBool,
829 &server_ptr->verbose,
830 &server_ptr->default_verbose,
831 value) == NULL)
833 goto fail_free_parameters;
836 value.i = 0;
837 if (jackctl_add_parameter(
838 &server_ptr->parameters,
839 "client-timeout",
840 "Client timeout limit in milliseconds.",
842 JackParamInt,
843 &server_ptr->client_timeout,
844 &server_ptr->default_client_timeout,
845 value) == NULL)
847 goto fail_free_parameters;
850 value.ui = 0;
851 if (jackctl_add_parameter(
852 &server_ptr->parameters,
853 "clock-source",
854 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
856 JackParamUInt,
857 &server_ptr->clock_source,
858 &server_ptr->default_clock_source,
859 value) == NULL)
861 goto fail_free_parameters;
864 value.ui = PORT_NUM;
865 if (jackctl_add_parameter(
866 &server_ptr->parameters,
867 "port-max",
868 "Maximum number of ports.",
870 JackParamUInt,
871 &server_ptr->port_max,
872 &server_ptr->default_port_max,
873 value) == NULL)
875 goto fail_free_parameters;
878 value.b = false;
879 if (jackctl_add_parameter(
880 &server_ptr->parameters,
881 "replace-registry",
882 "Replace shared memory registry.",
884 JackParamBool,
885 &server_ptr->replace_registry,
886 &server_ptr->default_replace_registry,
887 value) == NULL)
889 goto fail_free_parameters;
892 value.b = false;
893 if (jackctl_add_parameter(
894 &server_ptr->parameters,
895 "sync",
896 "Use server synchronous mode.",
898 JackParamBool,
899 &server_ptr->sync,
900 &server_ptr->default_sync,
901 value) == NULL)
903 goto fail_free_parameters;
906 value.c = JACK_DEFAULT_SELF_CONNECT_MODE;
907 if (jackctl_add_parameter(
908 &server_ptr->parameters,
909 "self-connect-mode",
910 "Self connect mode.",
911 "Whether JACK clients are allowed to connect their own ports",
912 JackParamChar,
913 &server_ptr->self_connect_mode,
914 &server_ptr->default_self_connect_mode,
915 value,
916 jack_constraint_compose_enum_char(
917 JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE,
918 self_connect_mode_constraint_descr_array)) == NULL)
920 goto fail_free_parameters;
923 JackServerGlobals::on_device_acquire = on_device_acquire;
924 JackServerGlobals::on_device_release = on_device_release;
926 if (!jackctl_drivers_load(server_ptr))
928 goto fail_free_parameters;
931 /* Allowed to fail */
932 jackctl_internals_load(server_ptr);
934 return server_ptr;
936 fail_free_parameters:
937 jackctl_server_free_parameters(server_ptr);
939 free(server_ptr);
941 fail:
942 return NULL;
945 SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
947 if (server_ptr) {
948 jackctl_server_free_drivers(server_ptr);
949 jackctl_server_free_internals(server_ptr);
950 jackctl_server_free_parameters(server_ptr);
951 free(server_ptr);
955 SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
957 return (server_ptr) ? server_ptr->drivers : NULL;
960 SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
962 if (server_ptr) {
963 server_ptr->engine->Stop();
964 return true;
965 } else {
966 return false;
970 SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
972 if (server_ptr) {
973 server_ptr->engine->Close();
974 delete server_ptr->engine;
976 /* clean up shared memory and files from this server instance */
977 jack_log("Cleaning up shared memory");
979 jack_cleanup_shm();
981 jack_log("Cleaning up files");
983 JackTools::CleanupFiles(server_ptr->name.str);
985 jack_log("Unregistering server `%s'", server_ptr->name.str);
987 jack_unregister_server(server_ptr->name.str);
989 server_ptr->engine = NULL;
991 return true;
992 } else {
993 return false;
997 SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
999 return (server_ptr) ? server_ptr->parameters : NULL;
1002 SERVER_EXPORT bool
1003 jackctl_server_open(
1004 jackctl_server *server_ptr,
1005 jackctl_driver *driver_ptr)
1007 JSList * paramlist = NULL;
1009 try {
1011 if (!server_ptr || !driver_ptr) {
1012 return false;
1015 int rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
1016 switch (rc)
1018 case EEXIST:
1019 jack_error("`%s' server already active", server_ptr->name.str);
1020 goto fail;
1021 case ENOSPC:
1022 jack_error("Too many servers already active");
1023 goto fail;
1024 case ENOMEM:
1025 jack_error("No access to shm registry");
1026 goto fail;
1029 jack_log("Server `%s' registered", server_ptr->name.str);
1031 /* clean up shared memory and files from any previous
1032 * instance of this server name */
1033 jack_cleanup_shm();
1034 JackTools::CleanupFiles(server_ptr->name.str);
1036 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) {
1037 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
1040 /* check port max value before allocating server */
1041 if (server_ptr->port_max.ui > PORT_NUM_MAX) {
1042 jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX);
1043 goto fail;
1046 /* get the engine/driver started */
1047 server_ptr->engine = new JackServer(
1048 server_ptr->sync.b,
1049 server_ptr->temporary.b,
1050 server_ptr->client_timeout.i,
1051 server_ptr->realtime.b,
1052 server_ptr->realtime_priority.i,
1053 server_ptr->port_max.ui,
1054 server_ptr->verbose.b,
1055 (jack_timer_type_t)server_ptr->clock_source.ui,
1056 server_ptr->self_connect_mode.c,
1057 server_ptr->name.str);
1058 if (server_ptr->engine == NULL)
1060 jack_error("Failed to create new JackServer object");
1061 goto fail_unregister;
1064 if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) goto fail_delete;
1065 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, paramlist);
1066 jackctl_destroy_param_list(paramlist);
1067 if (rc < 0)
1069 jack_error("JackServer::Open failed with %d", rc);
1070 goto fail_delete;
1073 return true;
1075 } catch (std::exception&) {
1076 jack_error("jackctl_server_open error...");
1077 jackctl_destroy_param_list(paramlist);
1080 fail_delete:
1081 delete server_ptr->engine;
1082 server_ptr->engine = NULL;
1084 fail_unregister:
1085 jack_log("Cleaning up shared memory");
1087 jack_cleanup_shm();
1089 jack_log("Cleaning up files");
1091 JackTools::CleanupFiles(server_ptr->name.str);
1093 jack_log("Unregistering server `%s'", server_ptr->name.str);
1095 jack_unregister_server(server_ptr->name.str);
1097 fail:
1098 return false;
1101 SERVER_EXPORT bool
1102 jackctl_server_start(
1103 jackctl_server *server_ptr)
1105 if (!server_ptr) {
1106 return false;
1107 } else {
1108 int rc = server_ptr->engine->Start();
1109 bool result = rc >= 0;
1110 if (! result)
1112 jack_error("JackServer::Start() failed with %d", rc);
1114 return result;
1118 SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
1120 return (driver_ptr) ? driver_ptr->desc_ptr->name : NULL;
1123 SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr)
1125 return (driver_ptr) ? (jackctl_driver_type_t)driver_ptr->desc_ptr->type : (jackctl_driver_type_t)0;
1128 SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
1130 return (driver_ptr) ? driver_ptr->parameters : NULL;
1133 SERVER_EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
1135 return (driver_ptr) ? driver_ptr->desc_ptr : NULL;
1138 SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
1140 return (parameter_ptr) ? parameter_ptr->name : NULL;
1143 SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
1145 return (parameter_ptr) ? parameter_ptr->short_description : NULL;
1148 SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
1150 return (parameter_ptr) ? parameter_ptr->long_description : NULL;
1153 SERVER_EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
1155 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0) : false;
1158 SERVER_EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
1160 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0): false;
1163 SERVER_EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
1165 if (!parameter_ptr) {
1166 return 0;
1169 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
1171 return 0;
1174 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
1177 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
1179 jack_driver_param_value_t * value_ptr;
1180 union jackctl_parameter_value jackctl_value;
1182 if (!parameter_ptr) {
1183 memset(&jackctl_value, 0, sizeof(jackctl_value));
1184 return jackctl_value;
1187 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1189 switch (parameter_ptr->type)
1191 case JackParamInt:
1192 jackctl_value.i = value_ptr->i;
1193 break;
1194 case JackParamUInt:
1195 jackctl_value.ui = value_ptr->ui;
1196 break;
1197 case JackParamChar:
1198 jackctl_value.c = value_ptr->c;
1199 break;
1200 case JackParamString:
1201 strcpy(jackctl_value.str, value_ptr->str);
1202 break;
1203 default:
1204 jack_error("Bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1205 assert(0);
1208 return jackctl_value;
1211 SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1213 return (parameter_ptr) ? parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc : NULL;
1216 SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1218 if (!parameter_ptr || !min_ptr || !max_ptr) {
1219 return;
1222 switch (parameter_ptr->type)
1224 case JackParamInt:
1225 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1226 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1227 return;
1228 case JackParamUInt:
1229 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1230 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1231 return;
1232 default:
1233 jack_error("Bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1234 assert(0);
1238 SERVER_EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1240 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0) : false;
1243 SERVER_EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1245 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0) : false;
1248 SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1250 return (parameter_ptr) ? parameter_ptr->type : (jackctl_param_type_t)0;
1253 SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1255 return (parameter_ptr) ? parameter_ptr->id : 0;
1258 SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1260 return (parameter_ptr) ? parameter_ptr->is_set : false;
1263 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1265 if (parameter_ptr) {
1266 return *parameter_ptr->value_ptr;
1267 } else {
1268 union jackctl_parameter_value jackctl_value;
1269 memset(&jackctl_value, 0, sizeof(jackctl_value));
1270 return jackctl_value;
1274 SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1276 if (!parameter_ptr) {
1277 return NULL;
1280 if (!parameter_ptr->is_set)
1282 return true;
1285 parameter_ptr->is_set = false;
1287 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1289 return true;
1292 SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1294 if (!parameter_ptr || !value_ptr) {
1295 return NULL;
1298 parameter_ptr->is_set = true;
1299 *parameter_ptr->value_ptr = *value_ptr;
1301 return true;
1304 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1306 if (parameter_ptr) {
1307 return *parameter_ptr->default_value_ptr;
1308 } else {
1309 union jackctl_parameter_value jackctl_value;
1310 memset(&jackctl_value, 0, sizeof(jackctl_value));
1311 return jackctl_value;
1315 // Internals clients
1317 SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1319 return (server_ptr) ? server_ptr->internals : NULL;
1322 SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1324 return (internal_ptr) ? internal_ptr->desc_ptr->name : NULL;
1327 SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1329 return (internal_ptr) ? internal_ptr->parameters : NULL;
1332 SERVER_EXPORT bool jackctl_server_load_internal(
1333 jackctl_server * server_ptr,
1334 jackctl_internal * internal)
1336 if (!server_ptr || !internal) {
1337 return false;
1340 int status;
1341 if (server_ptr->engine != NULL) {
1342 JSList * paramlist;
1343 if (!jackctl_create_param_list(internal->parameters, &paramlist)) return false;
1344 server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, paramlist, JackNullOption, &internal->refnum, -1, &status);
1345 jackctl_destroy_param_list(paramlist);
1346 return (internal->refnum > 0);
1347 } else {
1348 return false;
1352 SERVER_EXPORT bool jackctl_server_unload_internal(
1353 jackctl_server * server_ptr,
1354 jackctl_internal * internal)
1356 if (!server_ptr || !internal) {
1357 return false;
1360 int status;
1361 if (server_ptr->engine != NULL && internal->refnum > 0) {
1362 // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
1363 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1364 } else {
1365 return false;
1369 SERVER_EXPORT bool jackctl_server_load_session_file(
1370 jackctl_server * server_ptr,
1371 const char * file)
1373 if (!server_ptr || !file || !server_ptr->engine) {
1374 return false;
1377 return (server_ptr->engine->LoadInternalSessionFile(file) >= 0);
1380 SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1382 if (server_ptr && server_ptr->engine) {
1383 if (server_ptr->engine->IsRunning()) {
1384 jack_error("Cannot add a slave in a running server");
1385 return false;
1386 } else {
1387 JSList * paramlist;
1388 if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) return false;
1389 JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, paramlist);
1390 jackctl_destroy_param_list(paramlist);
1391 if (info) {
1392 driver_ptr->infos = jack_slist_append(driver_ptr->infos, info);
1393 return true;
1394 } else {
1395 return false;
1398 } else {
1399 return false;
1403 SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1405 if (server_ptr && server_ptr->engine) {
1406 if (server_ptr->engine->IsRunning()) {
1407 jack_error("Cannot remove a slave from a running server");
1408 return false;
1409 } else {
1410 if (driver_ptr->infos) {
1411 JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data;
1412 assert(info);
1413 driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info);
1414 server_ptr->engine->RemoveSlave(info);
1415 delete info;
1416 return true;
1417 } else {
1418 return false;
1421 } else {
1422 return false;
1426 SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1428 if (server_ptr && server_ptr->engine) {
1429 JSList * paramlist;
1430 if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) return false;
1431 bool ret = (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, paramlist) == 0);
1432 jackctl_destroy_param_list(paramlist);
1433 return ret;
1434 } else {
1435 return false;