Merge branch 'master' into no-self-connect
[jack2.git] / common / JackControlAPI.cpp
blobfd69b1fc23499e416ffe7ad8534b5a219038cc0e
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 #define SELF_CONNECT_MODE_ALLOW_CHAR ' '
51 #define SELF_CONNECT_MODE_FAIL_EXTERNAL_ONLY_CHAR 'E'
52 #define SELF_CONNECT_MODE_IGNORE_EXTERNAL_ONLY_CHAR 'e'
53 #define SELF_CONNECT_MODE_FAIL_ALL_CHAR 'A'
54 #define SELF_CONNECT_MODE_IGNORE_ALL_CHAR 'a'
55 #define SELF_CONNECT_MODES_COUNT 5
57 struct jackctl_server
59 JSList * drivers;
60 JSList * internals;
61 JSList * parameters;
63 class JackServer * engine;
65 /* string, server name */
66 union jackctl_parameter_value name;
67 union jackctl_parameter_value default_name;
69 /* bool, whether to be "realtime" */
70 union jackctl_parameter_value realtime;
71 union jackctl_parameter_value default_realtime;
73 /* int32_t */
74 union jackctl_parameter_value realtime_priority;
75 union jackctl_parameter_value default_realtime_priority;
77 /* bool, whether to exit once all clients have closed their connections */
78 union jackctl_parameter_value temporary;
79 union jackctl_parameter_value default_temporary;
81 /* bool, whether to be verbose */
82 union jackctl_parameter_value verbose;
83 union jackctl_parameter_value default_verbose;
85 /* int32_t, msecs; if zero, use period size. */
86 union jackctl_parameter_value client_timeout;
87 union jackctl_parameter_value default_client_timeout;
89 /* uint32_t, clock source type */
90 union jackctl_parameter_value clock_source;
91 union jackctl_parameter_value default_clock_source;
93 /* bool */
94 union jackctl_parameter_value replace_registry;
95 union jackctl_parameter_value default_replace_registry;
97 /* bool, synchronous or asynchronous engine mode */
98 union jackctl_parameter_value sync;
99 union jackctl_parameter_value default_sync;
101 /* char enum, self connect mode mode */
102 union jackctl_parameter_value self_connect_mode;
103 union jackctl_parameter_value default_self_connect_mode;
104 jack_driver_param_value_enum_t self_connect_mode_possible_values[SELF_CONNECT_MODES_COUNT];
105 jack_driver_param_constraint_desc_t self_connect_mode_constraint;
108 struct jackctl_driver
110 jack_driver_desc_t * desc_ptr;
111 JSList * parameters;
112 JSList * set_parameters;
113 JackDriverInfo* info;
116 struct jackctl_internal
118 jack_driver_desc_t * desc_ptr;
119 JSList * parameters;
120 JSList * set_parameters;
121 int refnum;
124 struct jackctl_parameter
126 const char * name;
127 const char * short_description;
128 const char * long_description;
129 jackctl_param_type_t type;
130 bool is_set;
131 union jackctl_parameter_value * value_ptr;
132 union jackctl_parameter_value * default_value_ptr;
134 union jackctl_parameter_value value;
135 union jackctl_parameter_value default_value;
136 struct jackctl_driver * driver_ptr;
137 char id;
138 jack_driver_param_t * driver_parameter_ptr;
139 jack_driver_param_constraint_desc_t * constraint_ptr;
142 static
143 struct jackctl_parameter *
144 jackctl_add_parameter(
145 JSList ** parameters_list_ptr_ptr,
146 const char * name,
147 const char * short_description,
148 const char * long_description,
149 jackctl_param_type_t type,
150 union jackctl_parameter_value * value_ptr,
151 union jackctl_parameter_value * default_value_ptr,
152 union jackctl_parameter_value value,
153 jack_driver_param_constraint_desc_t * constraint_ptr = NULL)
155 struct jackctl_parameter * parameter_ptr;
157 parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter));
158 if (parameter_ptr == NULL)
160 jack_error("Cannot allocate memory for jackctl_parameter structure.");
161 goto fail;
164 parameter_ptr->name = name;
165 parameter_ptr->short_description = short_description;
166 parameter_ptr->long_description = long_description;
167 parameter_ptr->type = type;
168 parameter_ptr->is_set = false;
170 if (value_ptr == NULL)
172 value_ptr = &parameter_ptr->value;
175 if (default_value_ptr == NULL)
177 default_value_ptr = &parameter_ptr->default_value;
180 parameter_ptr->value_ptr = value_ptr;
181 parameter_ptr->default_value_ptr = default_value_ptr;
183 *value_ptr = *default_value_ptr = value;
185 parameter_ptr->driver_ptr = NULL;
186 parameter_ptr->driver_parameter_ptr = NULL;
187 parameter_ptr->id = 0;
188 parameter_ptr->constraint_ptr = constraint_ptr;
190 *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
192 return parameter_ptr;
194 fail:
195 return NULL;
198 static
199 void
200 jackctl_free_driver_parameters(
201 struct jackctl_driver * driver_ptr)
203 JSList * next_node_ptr;
205 while (driver_ptr->parameters)
207 next_node_ptr = driver_ptr->parameters->next;
208 free(driver_ptr->parameters->data);
209 free(driver_ptr->parameters);
210 driver_ptr->parameters = next_node_ptr;
213 while (driver_ptr->set_parameters)
215 next_node_ptr = driver_ptr->set_parameters->next;
216 free(driver_ptr->set_parameters->data);
217 free(driver_ptr->set_parameters);
218 driver_ptr->set_parameters = next_node_ptr;
222 static
223 bool
224 jackctl_add_driver_parameters(
225 struct jackctl_driver * driver_ptr)
227 uint32_t i;
228 union jackctl_parameter_value jackctl_value;
229 jackctl_param_type_t jackctl_type;
230 struct jackctl_parameter * parameter_ptr;
231 jack_driver_param_desc_t * descriptor_ptr;
233 for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
235 descriptor_ptr = driver_ptr->desc_ptr->params + i;
237 switch (descriptor_ptr->type)
239 case JackDriverParamInt:
240 jackctl_type = JackParamInt;
241 jackctl_value.i = descriptor_ptr->value.i;
242 break;
243 case JackDriverParamUInt:
244 jackctl_type = JackParamUInt;
245 jackctl_value.ui = descriptor_ptr->value.ui;
246 break;
247 case JackDriverParamChar:
248 jackctl_type = JackParamChar;
249 jackctl_value.c = descriptor_ptr->value.c;
250 break;
251 case JackDriverParamString:
252 jackctl_type = JackParamString;
253 strcpy(jackctl_value.str, descriptor_ptr->value.str);
254 break;
255 case JackDriverParamBool:
256 jackctl_type = JackParamBool;
257 jackctl_value.b = descriptor_ptr->value.i;
258 break;
259 default:
260 jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type);
261 assert(0);
262 goto fail;
265 parameter_ptr = jackctl_add_parameter(
266 &driver_ptr->parameters,
267 descriptor_ptr->name,
268 descriptor_ptr->short_desc,
269 descriptor_ptr->long_desc,
270 jackctl_type,
271 NULL,
272 NULL,
273 jackctl_value,
274 descriptor_ptr->constraint);
276 if (parameter_ptr == NULL)
278 goto fail;
281 parameter_ptr->driver_ptr = driver_ptr;
282 parameter_ptr->id = descriptor_ptr->character;
285 return true;
287 fail:
288 jackctl_free_driver_parameters(driver_ptr);
290 return false;
293 static int
294 jackctl_drivers_load(
295 struct jackctl_server * server_ptr)
297 struct jackctl_driver * driver_ptr;
298 JSList *node_ptr;
299 JSList *descriptor_node_ptr;
301 descriptor_node_ptr = jack_drivers_load(NULL);
302 if (descriptor_node_ptr == NULL)
304 jack_error("could not find any drivers in driver directory!");
305 return false;
308 while (descriptor_node_ptr != NULL)
310 driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver));
311 if (driver_ptr == NULL)
313 jack_error("memory allocation of jackctl_driver structure failed.");
314 goto next;
317 driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
318 driver_ptr->parameters = NULL;
319 driver_ptr->set_parameters = NULL;
321 if (!jackctl_add_driver_parameters(driver_ptr))
323 assert(driver_ptr->parameters == NULL);
324 free(driver_ptr);
325 goto next;
328 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
330 next:
331 node_ptr = descriptor_node_ptr;
332 descriptor_node_ptr = descriptor_node_ptr->next;
333 free(node_ptr);
336 return true;
339 static
340 void
341 jackctl_server_free_drivers(
342 struct jackctl_server * server_ptr)
344 JSList * next_node_ptr;
345 struct jackctl_driver * driver_ptr;
347 while (server_ptr->drivers)
349 next_node_ptr = server_ptr->drivers->next;
350 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
352 jackctl_free_driver_parameters(driver_ptr);
353 free(driver_ptr->desc_ptr->params);
354 free(driver_ptr->desc_ptr);
355 free(driver_ptr);
357 free(server_ptr->drivers);
358 server_ptr->drivers = next_node_ptr;
362 static int
363 jackctl_internals_load(
364 struct jackctl_server * server_ptr)
366 struct jackctl_internal * internal_ptr;
367 JSList *node_ptr;
368 JSList *descriptor_node_ptr;
370 descriptor_node_ptr = jack_internals_load(NULL);
371 if (descriptor_node_ptr == NULL)
373 jack_error("could not find any internals in driver directory!");
374 return false;
377 while (descriptor_node_ptr != NULL)
379 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal));
380 if (internal_ptr == NULL)
382 jack_error("memory allocation of jackctl_driver structure failed.");
383 goto next;
386 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
387 internal_ptr->parameters = NULL;
388 internal_ptr->set_parameters = NULL;
390 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr))
392 assert(internal_ptr->parameters == NULL);
393 free(internal_ptr);
394 goto next;
397 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr);
399 next:
400 node_ptr = descriptor_node_ptr;
401 descriptor_node_ptr = descriptor_node_ptr->next;
402 free(node_ptr);
405 return true;
408 static
409 void
410 jackctl_server_free_internals(
411 struct jackctl_server * server_ptr)
413 JSList * next_node_ptr;
414 struct jackctl_internal * internal_ptr;
416 while (server_ptr->internals)
418 next_node_ptr = server_ptr->internals->next;
419 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data;
421 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr);
422 free(internal_ptr->desc_ptr->params);
423 free(internal_ptr->desc_ptr);
424 free(internal_ptr);
426 free(server_ptr->internals);
427 server_ptr->internals = next_node_ptr;
431 static
432 void
433 jackctl_server_free_parameters(
434 struct jackctl_server * server_ptr)
436 JSList * next_node_ptr;
438 while (server_ptr->parameters)
440 next_node_ptr = server_ptr->parameters->next;
441 free(server_ptr->parameters->data);
442 free(server_ptr->parameters);
443 server_ptr->parameters = next_node_ptr;
447 #ifdef WIN32
449 static HANDLE waitEvent;
451 static void do_nothing_handler(int signum)
453 printf("jack main caught signal %d\n", signum);
454 (void) signal(SIGINT, SIG_DFL);
455 SetEvent(waitEvent);
458 sigset_t
459 jackctl_setup_signals(
460 unsigned int flags)
462 if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
463 jack_error("CreateEvent fails err = %ld", GetLastError());
464 return 0;
467 (void) signal(SIGINT, do_nothing_handler);
468 (void) signal(SIGABRT, do_nothing_handler);
469 (void) signal(SIGTERM, do_nothing_handler);
471 return (sigset_t)waitEvent;
474 void jackctl_wait_signals(sigset_t signals)
476 if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) {
477 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
481 #else
483 static
484 void
485 do_nothing_handler(int sig)
487 /* this is used by the child (active) process, but it never
488 gets called unless we are already shutting down after
489 another signal.
491 char buf[64];
492 snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig);
495 EXPORT sigset_t
496 jackctl_setup_signals(
497 unsigned int flags)
499 sigset_t signals;
500 sigset_t allsignals;
501 struct sigaction action;
502 int i;
504 /* ensure that we are in our own process group so that
505 kill (SIG, -pgrp) does the right thing.
508 setsid();
510 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
512 /* what's this for?
514 POSIX says that signals are delivered like this:
516 * if a thread has blocked that signal, it is not
517 a candidate to receive the signal.
518 * of all threads not blocking the signal, pick
519 one at random, and deliver the signal.
521 this means that a simple-minded multi-threaded program can
522 expect to get POSIX signals delivered randomly to any one
523 of its threads,
525 here, we block all signals that we think we might receive
526 and want to catch. all "child" threads will inherit this
527 setting. if we create a thread that calls sigwait() on the
528 same set of signals, implicitly unblocking all those
529 signals. any of those signals that are delivered to the
530 process will be delivered to that thread, and that thread
531 alone. this makes cleanup for a signal-driven exit much
532 easier, since we know which thread is doing it and more
533 importantly, we are free to call async-unsafe functions,
534 because the code is executing in normal thread context
535 after a return from sigwait().
538 sigemptyset(&signals);
539 sigaddset(&signals, SIGHUP);
540 sigaddset(&signals, SIGINT);
541 sigaddset(&signals, SIGQUIT);
542 sigaddset(&signals, SIGPIPE);
543 sigaddset(&signals, SIGTERM);
544 sigaddset(&signals, SIGUSR1);
545 sigaddset(&signals, SIGUSR2);
547 /* all child threads will inherit this mask unless they
548 * explicitly reset it
551 pthread_sigmask(SIG_BLOCK, &signals, 0);
553 /* install a do-nothing handler because otherwise pthreads
554 behaviour is undefined when we enter sigwait.
557 sigfillset(&allsignals);
558 action.sa_handler = do_nothing_handler;
559 action.sa_mask = allsignals;
560 action.sa_flags = SA_RESTART|SA_RESETHAND;
562 for (i = 1; i < NSIG; i++)
564 if (sigismember (&signals, i))
566 sigaction(i, &action, 0);
570 return signals;
573 EXPORT void
574 jackctl_wait_signals(sigset_t signals)
576 int sig;
577 bool waiting = true;
579 while (waiting) {
580 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
581 sigwait(&signals);
582 #else
583 sigwait(&signals, &sig);
584 #endif
585 fprintf(stderr, "jack main caught signal %d\n", sig);
587 switch (sig) {
588 case SIGUSR1:
589 //jack_dump_configuration(engine, 1);
590 break;
591 case SIGUSR2:
592 // driver exit
593 waiting = false;
594 break;
595 case SIGTTOU:
596 break;
597 default:
598 waiting = false;
599 break;
603 if (sig != SIGSEGV) {
604 // unblock signals so we can see them during shutdown.
605 // this will help prod developers not to lose sight of
606 // bugs that cause segfaults etc. during shutdown.
607 sigprocmask(SIG_UNBLOCK, &signals, 0);
610 #endif
612 static
613 jack_driver_param_constraint_desc_t *
614 get_realtime_priority_constraint()
616 jack_driver_param_constraint_desc_t * constraint_ptr;
617 int min, max;
619 if (!jack_get_thread_realtime_priority_range(&min, &max))
621 return NULL;
624 //jack_info("realtime priority range is (%d,%d)", min, max);
626 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
627 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
629 constraint_ptr->constraint.range.min.i = min;
630 constraint_ptr->constraint.range.max.i = max;
632 return constraint_ptr;
635 EXPORT jackctl_server_t * jackctl_server_create(
636 bool (* on_device_acquire)(const char * device_name),
637 void (* on_device_release)(const char * device_name))
639 struct jackctl_server * server_ptr;
640 union jackctl_parameter_value value;
642 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
643 if (server_ptr == NULL)
645 jack_error("Cannot allocate memory for jackctl_server structure.");
646 goto fail;
649 server_ptr->drivers = NULL;
650 server_ptr->internals = NULL;
651 server_ptr->parameters = NULL;
652 server_ptr->engine = NULL;
654 strcpy(value.str, JACK_DEFAULT_SERVER_NAME);
655 if (jackctl_add_parameter(
656 &server_ptr->parameters,
657 "name",
658 "Server name to use.",
660 JackParamString,
661 &server_ptr->name,
662 &server_ptr->default_name,
663 value) == NULL)
665 goto fail_free_parameters;
668 value.b = false;
669 if (jackctl_add_parameter(
670 &server_ptr->parameters,
671 "realtime",
672 "Whether to use realtime mode.",
673 "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.",
674 JackParamBool,
675 &server_ptr->realtime,
676 &server_ptr->default_realtime,
677 value) == NULL)
679 goto fail_free_parameters;
682 value.i = 10;
683 if (jackctl_add_parameter(
684 &server_ptr->parameters,
685 "realtime-priority",
686 "Scheduler priority when running in realtime mode.",
688 JackParamInt,
689 &server_ptr->realtime_priority,
690 &server_ptr->default_realtime_priority,
691 value,
692 get_realtime_priority_constraint()) == NULL)
694 goto fail_free_parameters;
697 value.b = false;
698 if (jackctl_add_parameter(
699 &server_ptr->parameters,
700 "temporary",
701 "Exit once all clients have closed their connections.",
703 JackParamBool,
704 &server_ptr->temporary,
705 &server_ptr->default_temporary,
706 value) == NULL)
708 goto fail_free_parameters;
711 value.b = false;
712 if (jackctl_add_parameter(
713 &server_ptr->parameters,
714 "verbose",
715 "Verbose mode.",
717 JackParamBool,
718 &server_ptr->verbose,
719 &server_ptr->default_verbose,
720 value) == NULL)
722 goto fail_free_parameters;
725 value.i = 0;
726 if (jackctl_add_parameter(
727 &server_ptr->parameters,
728 "client-timeout",
729 "Client timeout limit in milliseconds.",
731 JackParamInt,
732 &server_ptr->client_timeout,
733 &server_ptr->default_client_timeout,
734 value) == NULL)
736 goto fail_free_parameters;
739 value.ui = 0;
740 if (jackctl_add_parameter(
741 &server_ptr->parameters,
742 "clock-source",
743 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
745 JackParamUInt,
746 &server_ptr->clock_source,
747 &server_ptr->default_clock_source,
748 value) == NULL)
750 goto fail_free_parameters;
753 value.b = false;
754 if (jackctl_add_parameter(
755 &server_ptr->parameters,
756 "replace-registry",
757 "Replace shared memory registry.",
759 JackParamBool,
760 &server_ptr->replace_registry,
761 &server_ptr->default_replace_registry,
762 value) == NULL)
764 goto fail_free_parameters;
767 value.b = false;
768 if (jackctl_add_parameter(
769 &server_ptr->parameters,
770 "sync",
771 "Use server synchronous mode.",
773 JackParamBool,
774 &server_ptr->sync,
775 &server_ptr->default_sync,
776 value) == NULL)
778 goto fail_free_parameters;
781 server_ptr->self_connect_mode_constraint.flags = JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
782 server_ptr->self_connect_mode_constraint.constraint.enumeration.count = SELF_CONNECT_MODES_COUNT;
783 server_ptr->self_connect_mode_constraint.constraint.enumeration.possible_values_array = server_ptr->self_connect_mode_possible_values;
785 server_ptr->self_connect_mode_possible_values[0].value.c = SELF_CONNECT_MODE_ALLOW_CHAR;
786 strcpy(server_ptr->self_connect_mode_possible_values[0].short_desc, "Don't restrict self connect requests");
788 server_ptr->self_connect_mode_possible_values[1].value.c = SELF_CONNECT_MODE_FAIL_EXTERNAL_ONLY_CHAR ;
789 strcpy(server_ptr->self_connect_mode_possible_values[1].short_desc, "Fail self connect requests to external ports only");
791 server_ptr->self_connect_mode_possible_values[2].value.c = SELF_CONNECT_MODE_IGNORE_EXTERNAL_ONLY_CHAR;
792 strcpy(server_ptr->self_connect_mode_possible_values[2].short_desc, "Ignore self connect requests to external ports only");
794 server_ptr->self_connect_mode_possible_values[3].value.c = SELF_CONNECT_MODE_FAIL_ALL_CHAR;
795 strcpy(server_ptr->self_connect_mode_possible_values[3].short_desc, "Fail all self connect requests");
797 server_ptr->self_connect_mode_possible_values[4].value.c = SELF_CONNECT_MODE_IGNORE_ALL_CHAR;
798 strcpy(server_ptr->self_connect_mode_possible_values[4].short_desc, "Ignore all self connect requests");
800 value.c = SELF_CONNECT_MODE_ALLOW_CHAR;
801 if (jackctl_add_parameter(
802 &server_ptr->parameters,
803 "self-connect-mode",
804 "Self connect mode.",
805 "Whether JACK clients are allowed to connect their own ports",
806 JackParamChar,
807 &server_ptr->self_connect_mode,
808 &server_ptr->default_self_connect_mode,
809 value,
810 &server_ptr->self_connect_mode_constraint) == NULL)
812 goto fail_free_parameters;
815 JackServerGlobals::on_device_acquire = on_device_acquire;
816 JackServerGlobals::on_device_release = on_device_release;
818 if (!jackctl_drivers_load(server_ptr))
820 goto fail_free_parameters;
823 /* Allowed to fail */
824 jackctl_internals_load(server_ptr);
826 return server_ptr;
828 fail_free_parameters:
829 jackctl_server_free_parameters(server_ptr);
831 free(server_ptr);
833 fail:
834 return NULL;
837 EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
839 jackctl_server_free_drivers(server_ptr);
840 jackctl_server_free_internals(server_ptr);
841 jackctl_server_free_parameters(server_ptr);
842 free(server_ptr);
845 EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
847 return server_ptr->drivers;
850 EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
852 server_ptr->engine->Stop();
853 server_ptr->engine->Close();
854 delete server_ptr->engine;
856 /* clean up shared memory and files from this server instance */
857 jack_log("cleaning up shared memory");
859 jack_cleanup_shm();
861 jack_log("cleaning up files");
863 JackTools::CleanupFiles(server_ptr->name.str);
865 jack_log("unregistering server `%s'", server_ptr->name.str);
867 jack_unregister_server(server_ptr->name.str);
869 server_ptr->engine = NULL;
871 return true;
874 EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
876 return server_ptr->parameters;
879 EXPORT bool
880 jackctl_server_start(
881 jackctl_server *server_ptr,
882 jackctl_driver *driver_ptr)
884 int rc;
885 JackSelfConnectMode self_connect_mode;
887 rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
888 switch (rc)
890 case EEXIST:
891 jack_error("`%s' server already active", server_ptr->name.str);
892 goto fail;
893 case ENOSPC:
894 jack_error("too many servers already active");
895 goto fail;
896 case ENOMEM:
897 jack_error("no access to shm registry");
898 goto fail;
901 jack_log("server `%s' registered", server_ptr->name.str);
903 /* clean up shared memory and files from any previous
904 * instance of this server name */
905 jack_cleanup_shm();
906 JackTools::CleanupFiles(server_ptr->name.str);
908 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0)
909 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
911 switch (server_ptr->self_connect_mode.c)
913 case SELF_CONNECT_MODE_ALLOW_CHAR:
914 self_connect_mode = JackSelfConnectAllow;
915 break;
916 case SELF_CONNECT_MODE_FAIL_EXTERNAL_ONLY_CHAR:
917 self_connect_mode = JackSelfConnectFailExternalOnly;
918 break;
919 case SELF_CONNECT_MODE_IGNORE_EXTERNAL_ONLY_CHAR:
920 self_connect_mode = JackSelfConnectIgnoreExternalOnly;
921 break;
922 case SELF_CONNECT_MODE_FAIL_ALL_CHAR:
923 self_connect_mode = JackSelfConnectFailAll;
924 break;
925 case SELF_CONNECT_MODE_IGNORE_ALL_CHAR:
926 self_connect_mode = JackSelfConnectIgnoreAll;
927 break;
928 default:
929 self_connect_mode = JACK_DEFAULT_SELF_CONNECT_MODE;
932 /* get the engine/driver started */
934 server_ptr->engine = new JackServer(
935 server_ptr->sync.b,
936 server_ptr->temporary.b,
937 server_ptr->client_timeout.i,
938 server_ptr->realtime.b,
939 server_ptr->realtime_priority.i,
940 server_ptr->verbose.b,
941 (jack_timer_type_t)server_ptr->clock_source.ui,
942 self_connect_mode,
943 server_ptr->name.str);
944 if (server_ptr->engine == NULL)
946 jack_error("Failed to create new JackServer object");
947 goto fail_unregister;
950 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters);
951 if (rc < 0)
953 jack_error("JackServer::Open() failed with %d", rc);
954 goto fail_delete;
957 rc = server_ptr->engine->Start();
958 if (rc < 0)
960 jack_error("JackServer::Start() failed with %d", rc);
961 goto fail_close;
964 return true;
966 fail_close:
967 server_ptr->engine->Close();
969 fail_delete:
970 delete server_ptr->engine;
971 server_ptr->engine = NULL;
973 fail_unregister:
974 jack_log("cleaning up shared memory");
976 jack_cleanup_shm();
978 jack_log("cleaning up files");
980 JackTools::CleanupFiles(server_ptr->name.str);
982 jack_log("unregistering server `%s'", server_ptr->name.str);
984 jack_unregister_server(server_ptr->name.str);
986 fail:
987 return false;
990 EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
992 return driver_ptr->desc_ptr->name;
995 EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
997 return driver_ptr->parameters;
1000 EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
1002 return driver_ptr->desc_ptr;
1005 EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
1007 return parameter_ptr->name;
1010 EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
1012 return parameter_ptr->short_description;
1015 EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
1017 return parameter_ptr->long_description;
1020 EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
1022 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0;
1025 EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
1027 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0;
1030 EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
1032 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
1034 return 0;
1037 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
1040 EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
1042 jack_driver_param_value_t * value_ptr;
1043 union jackctl_parameter_value jackctl_value;
1045 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1047 switch (parameter_ptr->type)
1049 case JackParamInt:
1050 jackctl_value.i = value_ptr->i;
1051 break;
1052 case JackParamUInt:
1053 jackctl_value.ui = value_ptr->ui;
1054 break;
1055 case JackParamChar:
1056 jackctl_value.c = value_ptr->c;
1057 break;
1058 case JackParamString:
1059 strcpy(jackctl_value.str, value_ptr->str);
1060 break;
1061 default:
1062 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1063 assert(0);
1066 return jackctl_value;
1069 EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1071 return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc;
1074 EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1076 switch (parameter_ptr->type)
1078 case JackParamInt:
1079 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1080 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1081 return;
1082 case JackParamUInt:
1083 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1084 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1085 return;
1086 default:
1087 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1088 assert(0);
1092 EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1094 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0;
1097 EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1099 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0;
1102 EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1104 return parameter_ptr->type;
1107 EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1109 return parameter_ptr->id;
1112 EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1114 return parameter_ptr->is_set;
1117 EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1119 return *parameter_ptr->value_ptr;
1122 EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1124 if (!parameter_ptr->is_set)
1126 return true;
1129 parameter_ptr->is_set = false;
1131 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1133 return true;
1136 EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1138 bool new_driver_parameter;
1140 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */
1141 if (parameter_ptr->driver_ptr != NULL)
1143 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
1144 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL;
1145 if (new_driver_parameter)
1147 /* jack_info("new driver parameter..."); */
1148 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t));
1149 if (parameter_ptr->driver_parameter_ptr == NULL)
1151 jack_error ("Allocation of jack_driver_param_t structure failed");
1152 return false;
1155 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id;
1156 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1159 switch (parameter_ptr->type)
1161 case JackParamInt:
1162 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i;
1163 break;
1164 case JackParamUInt:
1165 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui;
1166 break;
1167 case JackParamChar:
1168 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c;
1169 break;
1170 case JackParamString:
1171 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str);
1172 break;
1173 case JackParamBool:
1174 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b;
1175 break;
1176 default:
1177 jack_error("unknown parameter type %i", (int)parameter_ptr->type);
1178 assert(0);
1180 if (new_driver_parameter)
1182 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1185 return false;
1189 parameter_ptr->is_set = true;
1190 *parameter_ptr->value_ptr = *value_ptr;
1192 return true;
1195 EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1197 return *parameter_ptr->default_value_ptr;
1200 // Internals clients
1202 EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1204 return server_ptr->internals;
1207 EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1209 return internal_ptr->desc_ptr->name;
1212 EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1214 return internal_ptr->parameters;
1217 EXPORT bool jackctl_server_load_internal(
1218 jackctl_server * server_ptr,
1219 jackctl_internal * internal)
1221 int status;
1222 if (server_ptr->engine != NULL) {
1223 server_ptr->engine->InternalClientLoad(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, &status);
1224 return (internal->refnum > 0);
1225 } else {
1226 return false;
1230 EXPORT bool jackctl_server_unload_internal(
1231 jackctl_server * server_ptr,
1232 jackctl_internal * internal)
1234 int status;
1235 if (server_ptr->engine != NULL && internal->refnum > 0) {
1236 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1237 } else {
1238 return false;
1242 EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1244 if (server_ptr->engine != NULL) {
1245 driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters);
1246 return (driver_ptr->info != 0);
1247 } else {
1248 return false;
1252 EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1254 if (server_ptr->engine != NULL) {
1255 server_ptr->engine->RemoveSlave(driver_ptr->info);
1256 delete driver_ptr->info;
1257 return true;
1258 } else {
1259 return false;
1263 EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1265 if (server_ptr->engine != NULL) {
1266 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0);
1267 } else {
1268 return false;