Merge branch 'master' into develop
[jack2.git] / common / JackControlAPI.cpp
blobc13640a97baa2125b234b7a5a0e20db13f4a8381
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 return jackctl_server_create2(on_device_acquire, on_device_release, NULL);
753 SERVER_EXPORT jackctl_server_t * jackctl_server_create2(
754 bool (* on_device_acquire)(const char * device_name),
755 void (* on_device_release)(const char * device_name),
756 void (* on_device_reservation_loop)(void))
758 struct jackctl_server * server_ptr;
759 union jackctl_parameter_value value;
761 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
762 if (server_ptr == NULL)
764 jack_error("Cannot allocate memory for jackctl_server structure.");
765 goto fail;
768 server_ptr->drivers = NULL;
769 server_ptr->internals = NULL;
770 server_ptr->parameters = NULL;
771 server_ptr->engine = NULL;
773 strcpy(value.str, JackTools::DefaultServerName());
774 if (jackctl_add_parameter(
775 &server_ptr->parameters,
776 "name",
777 "Server name to use.",
779 JackParamString,
780 &server_ptr->name,
781 &server_ptr->default_name,
782 value) == NULL)
784 goto fail_free_parameters;
787 value.b = true;
788 if (jackctl_add_parameter(
789 &server_ptr->parameters,
790 "realtime",
791 "Whether to use realtime mode.",
792 "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.",
793 JackParamBool,
794 &server_ptr->realtime,
795 &server_ptr->default_realtime,
796 value) == NULL)
798 goto fail_free_parameters;
801 value.i = 10;
802 if (jackctl_add_parameter(
803 &server_ptr->parameters,
804 "realtime-priority",
805 "Scheduler priority when running in realtime mode.",
807 JackParamInt,
808 &server_ptr->realtime_priority,
809 &server_ptr->default_realtime_priority,
810 value,
811 get_realtime_priority_constraint()) == NULL)
813 goto fail_free_parameters;
816 value.b = false;
817 if (jackctl_add_parameter(
818 &server_ptr->parameters,
819 "temporary",
820 "Exit once all clients have closed their connections.",
822 JackParamBool,
823 &server_ptr->temporary,
824 &server_ptr->default_temporary,
825 value) == NULL)
827 goto fail_free_parameters;
830 value.b = false;
831 if (jackctl_add_parameter(
832 &server_ptr->parameters,
833 "verbose",
834 "Verbose mode.",
836 JackParamBool,
837 &server_ptr->verbose,
838 &server_ptr->default_verbose,
839 value) == NULL)
841 goto fail_free_parameters;
844 value.i = 0;
845 if (jackctl_add_parameter(
846 &server_ptr->parameters,
847 "client-timeout",
848 "Client timeout limit in milliseconds.",
850 JackParamInt,
851 &server_ptr->client_timeout,
852 &server_ptr->default_client_timeout,
853 value) == NULL)
855 goto fail_free_parameters;
858 value.ui = 0;
859 if (jackctl_add_parameter(
860 &server_ptr->parameters,
861 "clock-source",
862 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
864 JackParamUInt,
865 &server_ptr->clock_source,
866 &server_ptr->default_clock_source,
867 value) == NULL)
869 goto fail_free_parameters;
872 value.ui = PORT_NUM;
873 if (jackctl_add_parameter(
874 &server_ptr->parameters,
875 "port-max",
876 "Maximum number of ports.",
878 JackParamUInt,
879 &server_ptr->port_max,
880 &server_ptr->default_port_max,
881 value) == NULL)
883 goto fail_free_parameters;
886 value.b = false;
887 if (jackctl_add_parameter(
888 &server_ptr->parameters,
889 "replace-registry",
890 "Replace shared memory registry.",
892 JackParamBool,
893 &server_ptr->replace_registry,
894 &server_ptr->default_replace_registry,
895 value) == NULL)
897 goto fail_free_parameters;
900 value.b = false;
901 if (jackctl_add_parameter(
902 &server_ptr->parameters,
903 "sync",
904 "Use server synchronous mode.",
906 JackParamBool,
907 &server_ptr->sync,
908 &server_ptr->default_sync,
909 value) == NULL)
911 goto fail_free_parameters;
914 value.c = JACK_DEFAULT_SELF_CONNECT_MODE;
915 if (jackctl_add_parameter(
916 &server_ptr->parameters,
917 "self-connect-mode",
918 "Self connect mode.",
919 "Whether JACK clients are allowed to connect their own ports",
920 JackParamChar,
921 &server_ptr->self_connect_mode,
922 &server_ptr->default_self_connect_mode,
923 value,
924 jack_constraint_compose_enum_char(
925 JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE,
926 self_connect_mode_constraint_descr_array)) == NULL)
928 goto fail_free_parameters;
931 JackServerGlobals::on_device_acquire = on_device_acquire;
932 JackServerGlobals::on_device_release = on_device_release;
933 JackServerGlobals::on_device_reservation_loop = on_device_reservation_loop;
935 if (!jackctl_drivers_load(server_ptr))
937 goto fail_free_parameters;
940 /* Allowed to fail */
941 jackctl_internals_load(server_ptr);
943 return server_ptr;
945 fail_free_parameters:
946 jackctl_server_free_parameters(server_ptr);
948 free(server_ptr);
950 fail:
951 return NULL;
954 SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
956 if (server_ptr) {
957 jackctl_server_free_drivers(server_ptr);
958 jackctl_server_free_internals(server_ptr);
959 jackctl_server_free_parameters(server_ptr);
960 free(server_ptr);
964 SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
966 return (server_ptr) ? server_ptr->drivers : NULL;
969 SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
971 if (server_ptr) {
972 server_ptr->engine->Stop();
973 return true;
974 } else {
975 return false;
979 SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
981 if (server_ptr) {
982 server_ptr->engine->Close();
983 delete server_ptr->engine;
985 /* clean up shared memory and files from this server instance */
986 jack_log("Cleaning up shared memory");
988 jack_cleanup_shm();
990 jack_log("Cleaning up files");
992 JackTools::CleanupFiles(server_ptr->name.str);
994 jack_log("Unregistering server `%s'", server_ptr->name.str);
996 jack_unregister_server(server_ptr->name.str);
998 server_ptr->engine = NULL;
1000 return true;
1001 } else {
1002 return false;
1006 SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
1008 return (server_ptr) ? server_ptr->parameters : NULL;
1011 SERVER_EXPORT bool
1012 jackctl_server_open(
1013 jackctl_server *server_ptr,
1014 jackctl_driver *driver_ptr)
1016 JSList * paramlist = NULL;
1018 try {
1020 if (!server_ptr || !driver_ptr) {
1021 return false;
1024 int rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
1025 switch (rc)
1027 case EEXIST:
1028 jack_error("`%s' server already active", server_ptr->name.str);
1029 goto fail;
1030 case ENOSPC:
1031 jack_error("Too many servers already active");
1032 goto fail;
1033 case ENOMEM:
1034 jack_error("No access to shm registry");
1035 goto fail;
1038 jack_log("Server `%s' registered", server_ptr->name.str);
1040 /* clean up shared memory and files from any previous
1041 * instance of this server name */
1042 jack_cleanup_shm();
1043 JackTools::CleanupFiles(server_ptr->name.str);
1045 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) {
1046 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
1049 /* check port max value before allocating server */
1050 if (server_ptr->port_max.ui > PORT_NUM_MAX) {
1051 jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX);
1052 goto fail;
1055 /* get the engine/driver started */
1056 server_ptr->engine = new JackServer(
1057 server_ptr->sync.b,
1058 server_ptr->temporary.b,
1059 server_ptr->client_timeout.i,
1060 server_ptr->realtime.b,
1061 server_ptr->realtime_priority.i,
1062 server_ptr->port_max.ui,
1063 server_ptr->verbose.b,
1064 (jack_timer_type_t)server_ptr->clock_source.ui,
1065 server_ptr->self_connect_mode.c,
1066 server_ptr->name.str);
1067 if (server_ptr->engine == NULL)
1069 jack_error("Failed to create new JackServer object");
1070 goto fail_unregister;
1073 if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) goto fail_delete;
1074 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, paramlist);
1075 jackctl_destroy_param_list(paramlist);
1076 if (rc < 0)
1078 jack_error("JackServer::Open failed with %d", rc);
1079 goto fail_delete;
1082 return true;
1084 } catch (std::exception&) {
1085 jack_error("jackctl_server_open error...");
1086 jackctl_destroy_param_list(paramlist);
1089 fail_delete:
1090 delete server_ptr->engine;
1091 server_ptr->engine = NULL;
1093 fail_unregister:
1094 jack_log("Cleaning up shared memory");
1096 jack_cleanup_shm();
1098 jack_log("Cleaning up files");
1100 JackTools::CleanupFiles(server_ptr->name.str);
1102 jack_log("Unregistering server `%s'", server_ptr->name.str);
1104 jack_unregister_server(server_ptr->name.str);
1106 fail:
1107 return false;
1110 SERVER_EXPORT bool
1111 jackctl_server_start(
1112 jackctl_server *server_ptr)
1114 if (!server_ptr) {
1115 return false;
1116 } else {
1117 int rc = server_ptr->engine->Start();
1118 bool result = rc >= 0;
1119 if (! result)
1121 jack_error("JackServer::Start() failed with %d", rc);
1123 return result;
1127 SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
1129 return (driver_ptr) ? driver_ptr->desc_ptr->name : NULL;
1132 SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr)
1134 return (driver_ptr) ? (jackctl_driver_type_t)driver_ptr->desc_ptr->type : (jackctl_driver_type_t)0;
1137 SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
1139 return (driver_ptr) ? driver_ptr->parameters : NULL;
1142 SERVER_EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
1144 return (driver_ptr) ? driver_ptr->desc_ptr : NULL;
1147 SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
1149 return (parameter_ptr) ? parameter_ptr->name : NULL;
1152 SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
1154 return (parameter_ptr) ? parameter_ptr->short_description : NULL;
1157 SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
1159 return (parameter_ptr) ? parameter_ptr->long_description : NULL;
1162 SERVER_EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
1164 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0) : false;
1167 SERVER_EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
1169 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0): false;
1172 SERVER_EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
1174 if (!parameter_ptr) {
1175 return 0;
1178 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
1180 return 0;
1183 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
1186 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
1188 jack_driver_param_value_t * value_ptr;
1189 union jackctl_parameter_value jackctl_value;
1191 if (!parameter_ptr) {
1192 memset(&jackctl_value, 0, sizeof(jackctl_value));
1193 return jackctl_value;
1196 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1198 switch (parameter_ptr->type)
1200 case JackParamInt:
1201 jackctl_value.i = value_ptr->i;
1202 break;
1203 case JackParamUInt:
1204 jackctl_value.ui = value_ptr->ui;
1205 break;
1206 case JackParamChar:
1207 jackctl_value.c = value_ptr->c;
1208 break;
1209 case JackParamString:
1210 strcpy(jackctl_value.str, value_ptr->str);
1211 break;
1212 default:
1213 jack_error("Bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1214 assert(0);
1217 return jackctl_value;
1220 SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1222 return (parameter_ptr) ? parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc : NULL;
1225 SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1227 if (!parameter_ptr || !min_ptr || !max_ptr) {
1228 return;
1231 switch (parameter_ptr->type)
1233 case JackParamInt:
1234 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1235 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1236 return;
1237 case JackParamUInt:
1238 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1239 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1240 return;
1241 default:
1242 jack_error("Bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1243 assert(0);
1247 SERVER_EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1249 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0) : false;
1252 SERVER_EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1254 return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0) : false;
1257 SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1259 return (parameter_ptr) ? parameter_ptr->type : (jackctl_param_type_t)0;
1262 SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1264 return (parameter_ptr) ? parameter_ptr->id : 0;
1267 SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1269 return (parameter_ptr) ? parameter_ptr->is_set : false;
1272 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1274 if (parameter_ptr) {
1275 return *parameter_ptr->value_ptr;
1276 } else {
1277 union jackctl_parameter_value jackctl_value;
1278 memset(&jackctl_value, 0, sizeof(jackctl_value));
1279 return jackctl_value;
1283 SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1285 if (!parameter_ptr) {
1286 return false;
1289 if (!parameter_ptr->is_set)
1291 return true;
1294 parameter_ptr->is_set = false;
1296 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1298 return true;
1301 SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1303 if (!parameter_ptr || !value_ptr) {
1304 return false;
1307 parameter_ptr->is_set = true;
1308 *parameter_ptr->value_ptr = *value_ptr;
1310 return true;
1313 SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1315 if (parameter_ptr) {
1316 return *parameter_ptr->default_value_ptr;
1317 } else {
1318 union jackctl_parameter_value jackctl_value;
1319 memset(&jackctl_value, 0, sizeof(jackctl_value));
1320 return jackctl_value;
1324 // Internals clients
1326 SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1328 return (server_ptr) ? server_ptr->internals : NULL;
1331 SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1333 return (internal_ptr) ? internal_ptr->desc_ptr->name : NULL;
1336 SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1338 return (internal_ptr) ? internal_ptr->parameters : NULL;
1341 SERVER_EXPORT bool jackctl_server_load_internal(
1342 jackctl_server * server_ptr,
1343 jackctl_internal * internal)
1345 if (!server_ptr || !internal) {
1346 return false;
1349 int status;
1350 if (server_ptr->engine != NULL) {
1351 JSList * paramlist;
1352 if (!jackctl_create_param_list(internal->parameters, &paramlist)) return false;
1353 server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, paramlist, JackNullOption, &internal->refnum, -1, &status);
1354 jackctl_destroy_param_list(paramlist);
1355 return (internal->refnum > 0);
1356 } else {
1357 return false;
1361 SERVER_EXPORT bool jackctl_server_unload_internal(
1362 jackctl_server * server_ptr,
1363 jackctl_internal * internal)
1365 if (!server_ptr || !internal) {
1366 return false;
1369 int status;
1370 if (server_ptr->engine != NULL && internal->refnum > 0) {
1371 // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
1372 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1373 } else {
1374 return false;
1378 SERVER_EXPORT bool jackctl_server_load_session_file(
1379 jackctl_server * server_ptr,
1380 const char * file)
1382 if (!server_ptr || !file || !server_ptr->engine) {
1383 return false;
1386 return (server_ptr->engine->LoadInternalSessionFile(file) >= 0);
1389 SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1391 if (server_ptr && server_ptr->engine) {
1392 if (server_ptr->engine->IsRunning()) {
1393 jack_error("Cannot add a slave in a running server");
1394 return false;
1395 } else {
1396 JSList * paramlist;
1397 if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) return false;
1398 JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, paramlist);
1399 jackctl_destroy_param_list(paramlist);
1400 if (info) {
1401 driver_ptr->infos = jack_slist_append(driver_ptr->infos, info);
1402 return true;
1403 } else {
1404 return false;
1407 } else {
1408 return false;
1412 SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1414 if (server_ptr && server_ptr->engine) {
1415 if (server_ptr->engine->IsRunning()) {
1416 jack_error("Cannot remove a slave from a running server");
1417 return false;
1418 } else {
1419 if (driver_ptr->infos) {
1420 JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data;
1421 assert(info);
1422 driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info);
1423 server_ptr->engine->RemoveSlave(info);
1424 delete info;
1425 return true;
1426 } else {
1427 return false;
1430 } else {
1431 return false;
1435 SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1437 if (server_ptr && server_ptr->engine) {
1438 JSList * paramlist;
1439 if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) return false;
1440 bool ret = (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, paramlist) == 0);
1441 jackctl_destroy_param_list(paramlist);
1442 return ret;
1443 } else {
1444 return false;