JackWeakAPI now working.
[jack2.git] / common / JackControlAPI.cpp
blob37eeb88a4308d5a731819437ef5b0cf3abceebc6
1 // u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */
2 /*
3 JACK control API implementation
5 Copyright (C) 2008 Nedko Arnaudov
6 Copyright (C) 2008 Grame
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #ifndef WIN32
24 #include <stdint.h>
25 #include <dirent.h>
26 #include <pthread.h>
27 #endif
29 #include "types.h"
30 #include <string.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <assert.h>
34 #include <signal.h>
36 #include "jslist.h"
37 #include "driver_interface.h"
38 #include "JackError.h"
39 #include "JackServer.h"
40 #include "shm.h"
41 #include "JackTools.h"
42 #include "JackControlAPI.h"
43 #include "JackLockedEngine.h"
44 #include "JackConstants.h"
45 #include "JackDriverLoader.h"
46 #include "JackServerGlobals.h"
48 using namespace Jack;
50 struct jackctl_server
52 JSList * drivers;
53 JSList * internals;
54 JSList * parameters;
56 class JackServer * engine;
58 /* string, server name */
59 union jackctl_parameter_value name;
60 union jackctl_parameter_value default_name;
62 /* bool, whether to be "realtime" */
63 union jackctl_parameter_value realtime;
64 union jackctl_parameter_value default_realtime;
66 /* int32_t */
67 union jackctl_parameter_value realtime_priority;
68 union jackctl_parameter_value default_realtime_priority;
70 /* bool, whether to exit once all clients have closed their connections */
71 union jackctl_parameter_value temporary;
72 union jackctl_parameter_value default_temporary;
74 /* bool, whether to be verbose */
75 union jackctl_parameter_value verbose;
76 union jackctl_parameter_value default_verbose;
78 /* int32_t, msecs; if zero, use period size. */
79 union jackctl_parameter_value client_timeout;
80 union jackctl_parameter_value default_client_timeout;
82 /* uint32_t, clock source type */
83 union jackctl_parameter_value clock_source;
84 union jackctl_parameter_value default_clock_source;
86 /* bool */
87 union jackctl_parameter_value replace_registry;
88 union jackctl_parameter_value default_replace_registry;
90 /* bool, synchronous or asynchronous engine mode */
91 union jackctl_parameter_value sync;
92 union jackctl_parameter_value default_sync;
95 struct jackctl_driver
97 jack_driver_desc_t * desc_ptr;
98 JSList * parameters;
99 JSList * set_parameters;
100 JackDriverInfo* info;
103 struct jackctl_internal
105 jack_driver_desc_t * desc_ptr;
106 JSList * parameters;
107 JSList * set_parameters;
108 int refnum;
111 struct jackctl_parameter
113 const char * name;
114 const char * short_description;
115 const char * long_description;
116 jackctl_param_type_t type;
117 bool is_set;
118 union jackctl_parameter_value * value_ptr;
119 union jackctl_parameter_value * default_value_ptr;
121 union jackctl_parameter_value value;
122 union jackctl_parameter_value default_value;
123 struct jackctl_driver * driver_ptr;
124 char id;
125 jack_driver_param_t * driver_parameter_ptr;
126 jack_driver_param_constraint_desc_t * constraint_ptr;
129 static
130 struct jackctl_parameter *
131 jackctl_add_parameter(
132 JSList ** parameters_list_ptr_ptr,
133 const char * name,
134 const char * short_description,
135 const char * long_description,
136 jackctl_param_type_t type,
137 union jackctl_parameter_value * value_ptr,
138 union jackctl_parameter_value * default_value_ptr,
139 union jackctl_parameter_value value,
140 jack_driver_param_constraint_desc_t * constraint_ptr = NULL)
142 struct jackctl_parameter * parameter_ptr;
144 parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter));
145 if (parameter_ptr == NULL)
147 jack_error("Cannot allocate memory for jackctl_parameter structure.");
148 goto fail;
151 parameter_ptr->name = name;
152 parameter_ptr->short_description = short_description;
153 parameter_ptr->long_description = long_description;
154 parameter_ptr->type = type;
155 parameter_ptr->is_set = false;
157 if (value_ptr == NULL)
159 value_ptr = &parameter_ptr->value;
162 if (default_value_ptr == NULL)
164 default_value_ptr = &parameter_ptr->default_value;
167 parameter_ptr->value_ptr = value_ptr;
168 parameter_ptr->default_value_ptr = default_value_ptr;
170 *value_ptr = *default_value_ptr = value;
172 parameter_ptr->driver_ptr = NULL;
173 parameter_ptr->driver_parameter_ptr = NULL;
174 parameter_ptr->id = 0;
175 parameter_ptr->constraint_ptr = constraint_ptr;
177 *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
179 return parameter_ptr;
181 fail:
182 return NULL;
185 static
186 void
187 jackctl_free_driver_parameters(
188 struct jackctl_driver * driver_ptr)
190 JSList * next_node_ptr;
192 while (driver_ptr->parameters)
194 next_node_ptr = driver_ptr->parameters->next;
195 free(driver_ptr->parameters->data);
196 free(driver_ptr->parameters);
197 driver_ptr->parameters = next_node_ptr;
200 while (driver_ptr->set_parameters)
202 next_node_ptr = driver_ptr->set_parameters->next;
203 free(driver_ptr->set_parameters->data);
204 free(driver_ptr->set_parameters);
205 driver_ptr->set_parameters = next_node_ptr;
209 static
210 bool
211 jackctl_add_driver_parameters(
212 struct jackctl_driver * driver_ptr)
214 uint32_t i;
215 union jackctl_parameter_value jackctl_value;
216 jackctl_param_type_t jackctl_type;
217 struct jackctl_parameter * parameter_ptr;
218 jack_driver_param_desc_t * descriptor_ptr;
220 for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
222 descriptor_ptr = driver_ptr->desc_ptr->params + i;
224 switch (descriptor_ptr->type)
226 case JackDriverParamInt:
227 jackctl_type = JackParamInt;
228 jackctl_value.i = descriptor_ptr->value.i;
229 break;
230 case JackDriverParamUInt:
231 jackctl_type = JackParamUInt;
232 jackctl_value.ui = descriptor_ptr->value.ui;
233 break;
234 case JackDriverParamChar:
235 jackctl_type = JackParamChar;
236 jackctl_value.c = descriptor_ptr->value.c;
237 break;
238 case JackDriverParamString:
239 jackctl_type = JackParamString;
240 strcpy(jackctl_value.str, descriptor_ptr->value.str);
241 break;
242 case JackDriverParamBool:
243 jackctl_type = JackParamBool;
244 jackctl_value.b = descriptor_ptr->value.i;
245 break;
246 default:
247 jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type);
248 assert(0);
249 goto fail;
252 parameter_ptr = jackctl_add_parameter(
253 &driver_ptr->parameters,
254 descriptor_ptr->name,
255 descriptor_ptr->short_desc,
256 descriptor_ptr->long_desc,
257 jackctl_type,
258 NULL,
259 NULL,
260 jackctl_value,
261 descriptor_ptr->constraint);
263 if (parameter_ptr == NULL)
265 goto fail;
268 parameter_ptr->driver_ptr = driver_ptr;
269 parameter_ptr->id = descriptor_ptr->character;
272 return true;
274 fail:
275 jackctl_free_driver_parameters(driver_ptr);
277 return false;
280 static int
281 jackctl_drivers_load(
282 struct jackctl_server * server_ptr)
284 struct jackctl_driver * driver_ptr;
285 JSList *node_ptr;
286 JSList *descriptor_node_ptr;
288 descriptor_node_ptr = jack_drivers_load(NULL);
289 if (descriptor_node_ptr == NULL)
291 jack_error("could not find any drivers in driver directory!");
292 return false;
295 while (descriptor_node_ptr != NULL)
297 driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver));
298 if (driver_ptr == NULL)
300 jack_error("memory allocation of jackctl_driver structure failed.");
301 goto next;
304 driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
305 driver_ptr->parameters = NULL;
306 driver_ptr->set_parameters = NULL;
308 if (!jackctl_add_driver_parameters(driver_ptr))
310 assert(driver_ptr->parameters == NULL);
311 free(driver_ptr);
312 goto next;
315 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
317 next:
318 node_ptr = descriptor_node_ptr;
319 descriptor_node_ptr = descriptor_node_ptr->next;
320 free(node_ptr);
323 return true;
326 static
327 void
328 jackctl_server_free_drivers(
329 struct jackctl_server * server_ptr)
331 JSList * next_node_ptr;
332 struct jackctl_driver * driver_ptr;
334 while (server_ptr->drivers)
336 next_node_ptr = server_ptr->drivers->next;
337 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
339 jackctl_free_driver_parameters(driver_ptr);
340 free(driver_ptr->desc_ptr->params);
341 free(driver_ptr->desc_ptr);
342 free(driver_ptr);
344 free(server_ptr->drivers);
345 server_ptr->drivers = next_node_ptr;
349 static int
350 jackctl_internals_load(
351 struct jackctl_server * server_ptr)
353 struct jackctl_internal * internal_ptr;
354 JSList *node_ptr;
355 JSList *descriptor_node_ptr;
357 descriptor_node_ptr = jack_internals_load(NULL);
358 if (descriptor_node_ptr == NULL)
360 jack_error("could not find any internals in driver directory!");
361 return false;
364 while (descriptor_node_ptr != NULL)
366 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal));
367 if (internal_ptr == NULL)
369 jack_error("memory allocation of jackctl_driver structure failed.");
370 goto next;
373 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
374 internal_ptr->parameters = NULL;
375 internal_ptr->set_parameters = NULL;
377 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr))
379 assert(internal_ptr->parameters == NULL);
380 free(internal_ptr);
381 goto next;
384 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr);
386 next:
387 node_ptr = descriptor_node_ptr;
388 descriptor_node_ptr = descriptor_node_ptr->next;
389 free(node_ptr);
392 return true;
395 static
396 void
397 jackctl_server_free_internals(
398 struct jackctl_server * server_ptr)
400 JSList * next_node_ptr;
401 struct jackctl_internal * internal_ptr;
403 while (server_ptr->internals)
405 next_node_ptr = server_ptr->internals->next;
406 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data;
408 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr);
409 free(internal_ptr->desc_ptr->params);
410 free(internal_ptr->desc_ptr);
411 free(internal_ptr);
413 free(server_ptr->internals);
414 server_ptr->internals = next_node_ptr;
418 static
419 void
420 jackctl_server_free_parameters(
421 struct jackctl_server * server_ptr)
423 JSList * next_node_ptr;
425 while (server_ptr->parameters)
427 next_node_ptr = server_ptr->parameters->next;
428 free(server_ptr->parameters->data);
429 free(server_ptr->parameters);
430 server_ptr->parameters = next_node_ptr;
434 #ifdef WIN32
436 static HANDLE waitEvent;
438 static void do_nothing_handler(int signum)
440 printf("jack main caught signal %d\n", signum);
441 (void) signal(SIGINT, SIG_DFL);
442 SetEvent(waitEvent);
445 sigset_t
446 jackctl_setup_signals(
447 unsigned int flags)
449 if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
450 jack_error("CreateEvent fails err = %ld", GetLastError());
451 return 0;
454 (void) signal(SIGINT, do_nothing_handler);
455 (void) signal(SIGABRT, do_nothing_handler);
456 (void) signal(SIGTERM, do_nothing_handler);
458 return (sigset_t)waitEvent;
461 void jackctl_wait_signals(sigset_t signals)
463 if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) {
464 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
468 #else
470 static
471 void
472 do_nothing_handler(int sig)
474 /* this is used by the child (active) process, but it never
475 gets called unless we are already shutting down after
476 another signal.
478 char buf[64];
479 snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig);
482 EXPORT sigset_t
483 jackctl_setup_signals(
484 unsigned int flags)
486 sigset_t signals;
487 sigset_t allsignals;
488 struct sigaction action;
489 int i;
491 /* ensure that we are in our own process group so that
492 kill (SIG, -pgrp) does the right thing.
495 setsid();
497 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
499 /* what's this for?
501 POSIX says that signals are delivered like this:
503 * if a thread has blocked that signal, it is not
504 a candidate to receive the signal.
505 * of all threads not blocking the signal, pick
506 one at random, and deliver the signal.
508 this means that a simple-minded multi-threaded program can
509 expect to get POSIX signals delivered randomly to any one
510 of its threads,
512 here, we block all signals that we think we might receive
513 and want to catch. all "child" threads will inherit this
514 setting. if we create a thread that calls sigwait() on the
515 same set of signals, implicitly unblocking all those
516 signals. any of those signals that are delivered to the
517 process will be delivered to that thread, and that thread
518 alone. this makes cleanup for a signal-driven exit much
519 easier, since we know which thread is doing it and more
520 importantly, we are free to call async-unsafe functions,
521 because the code is executing in normal thread context
522 after a return from sigwait().
525 sigemptyset(&signals);
526 sigaddset(&signals, SIGHUP);
527 sigaddset(&signals, SIGINT);
528 sigaddset(&signals, SIGQUIT);
529 sigaddset(&signals, SIGPIPE);
530 sigaddset(&signals, SIGTERM);
531 sigaddset(&signals, SIGUSR1);
532 sigaddset(&signals, SIGUSR2);
534 /* all child threads will inherit this mask unless they
535 * explicitly reset it
538 pthread_sigmask(SIG_BLOCK, &signals, 0);
540 /* install a do-nothing handler because otherwise pthreads
541 behaviour is undefined when we enter sigwait.
544 sigfillset(&allsignals);
545 action.sa_handler = do_nothing_handler;
546 action.sa_mask = allsignals;
547 action.sa_flags = SA_RESTART|SA_RESETHAND;
549 for (i = 1; i < NSIG; i++)
551 if (sigismember (&signals, i))
553 sigaction(i, &action, 0);
557 return signals;
560 EXPORT void
561 jackctl_wait_signals(sigset_t signals)
563 int sig;
564 bool waiting = true;
566 while (waiting) {
567 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
568 sigwait(&signals);
569 #else
570 sigwait(&signals, &sig);
571 #endif
572 fprintf(stderr, "jack main caught signal %d\n", sig);
574 switch (sig) {
575 case SIGUSR1:
576 //jack_dump_configuration(engine, 1);
577 break;
578 case SIGUSR2:
579 // driver exit
580 waiting = false;
581 break;
582 case SIGTTOU:
583 break;
584 default:
585 waiting = false;
586 break;
590 if (sig != SIGSEGV) {
591 // unblock signals so we can see them during shutdown.
592 // this will help prod developers not to lose sight of
593 // bugs that cause segfaults etc. during shutdown.
594 sigprocmask(SIG_UNBLOCK, &signals, 0);
597 #endif
599 static
600 jack_driver_param_constraint_desc_t *
601 get_realtime_priority_constraint()
603 jack_driver_param_constraint_desc_t * constraint_ptr;
604 int min, max;
606 if (!jack_get_thread_realtime_priority_range(&min, &max))
608 return NULL;
611 //jack_info("realtime priority range is (%d,%d)", min, max);
613 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
614 if (constraint_ptr == NULL)
616 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
617 return NULL;
619 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
621 constraint_ptr->constraint.range.min.i = min;
622 constraint_ptr->constraint.range.max.i = max;
624 return constraint_ptr;
627 EXPORT jackctl_server_t * jackctl_server_create(
628 bool (* on_device_acquire)(const char * device_name),
629 void (* on_device_release)(const char * device_name))
631 struct jackctl_server * server_ptr;
632 union jackctl_parameter_value value;
634 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
635 if (server_ptr == NULL)
637 jack_error("Cannot allocate memory for jackctl_server structure.");
638 goto fail;
641 server_ptr->drivers = NULL;
642 server_ptr->internals = NULL;
643 server_ptr->parameters = NULL;
644 server_ptr->engine = NULL;
646 strcpy(value.str, JACK_DEFAULT_SERVER_NAME);
647 if (jackctl_add_parameter(
648 &server_ptr->parameters,
649 "name",
650 "Server name to use.",
652 JackParamString,
653 &server_ptr->name,
654 &server_ptr->default_name,
655 value) == NULL)
657 goto fail_free_parameters;
660 value.b = false;
661 if (jackctl_add_parameter(
662 &server_ptr->parameters,
663 "realtime",
664 "Whether to use realtime mode.",
665 "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.",
666 JackParamBool,
667 &server_ptr->realtime,
668 &server_ptr->default_realtime,
669 value) == NULL)
671 goto fail_free_parameters;
674 value.i = 10;
675 if (jackctl_add_parameter(
676 &server_ptr->parameters,
677 "realtime-priority",
678 "Scheduler priority when running in realtime mode.",
680 JackParamInt,
681 &server_ptr->realtime_priority,
682 &server_ptr->default_realtime_priority,
683 value,
684 get_realtime_priority_constraint()) == NULL)
686 goto fail_free_parameters;
689 value.b = false;
690 if (jackctl_add_parameter(
691 &server_ptr->parameters,
692 "temporary",
693 "Exit once all clients have closed their connections.",
695 JackParamBool,
696 &server_ptr->temporary,
697 &server_ptr->default_temporary,
698 value) == NULL)
700 goto fail_free_parameters;
703 value.b = false;
704 if (jackctl_add_parameter(
705 &server_ptr->parameters,
706 "verbose",
707 "Verbose mode.",
709 JackParamBool,
710 &server_ptr->verbose,
711 &server_ptr->default_verbose,
712 value) == NULL)
714 goto fail_free_parameters;
717 value.i = 0;
718 if (jackctl_add_parameter(
719 &server_ptr->parameters,
720 "client-timeout",
721 "Client timeout limit in milliseconds.",
723 JackParamInt,
724 &server_ptr->client_timeout,
725 &server_ptr->default_client_timeout,
726 value) == NULL)
728 goto fail_free_parameters;
731 value.ui = 0;
732 if (jackctl_add_parameter(
733 &server_ptr->parameters,
734 "clock-source",
735 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
737 JackParamUInt,
738 &server_ptr->clock_source,
739 &server_ptr->default_clock_source,
740 value) == NULL)
742 goto fail_free_parameters;
745 value.b = false;
746 if (jackctl_add_parameter(
747 &server_ptr->parameters,
748 "replace-registry",
749 "Replace shared memory registry.",
751 JackParamBool,
752 &server_ptr->replace_registry,
753 &server_ptr->default_replace_registry,
754 value) == NULL)
756 goto fail_free_parameters;
759 value.b = false;
760 if (jackctl_add_parameter(
761 &server_ptr->parameters,
762 "sync",
763 "Use server synchronous mode.",
765 JackParamBool,
766 &server_ptr->sync,
767 &server_ptr->default_sync,
768 value) == NULL)
770 goto fail_free_parameters;
773 JackServerGlobals::on_device_acquire = on_device_acquire;
774 JackServerGlobals::on_device_release = on_device_release;
776 if (!jackctl_drivers_load(server_ptr))
778 goto fail_free_parameters;
781 /* Allowed to fail */
782 jackctl_internals_load(server_ptr);
784 return server_ptr;
786 fail_free_parameters:
787 jackctl_server_free_parameters(server_ptr);
789 free(server_ptr);
791 fail:
792 return NULL;
795 EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
797 jackctl_server_free_drivers(server_ptr);
798 jackctl_server_free_internals(server_ptr);
799 jackctl_server_free_parameters(server_ptr);
800 free(server_ptr);
803 EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
805 return server_ptr->drivers;
808 EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
810 server_ptr->engine->Stop();
811 server_ptr->engine->Close();
812 delete server_ptr->engine;
814 /* clean up shared memory and files from this server instance */
815 jack_log("cleaning up shared memory");
817 jack_cleanup_shm();
819 jack_log("cleaning up files");
821 JackTools::CleanupFiles(server_ptr->name.str);
823 jack_log("unregistering server `%s'", server_ptr->name.str);
825 jack_unregister_server(server_ptr->name.str);
827 server_ptr->engine = NULL;
829 return true;
832 EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
834 return server_ptr->parameters;
837 EXPORT bool
838 jackctl_server_start(
839 jackctl_server *server_ptr,
840 jackctl_driver *driver_ptr)
842 int rc;
844 rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
845 switch (rc)
847 case EEXIST:
848 jack_error("`%s' server already active", server_ptr->name.str);
849 goto fail;
850 case ENOSPC:
851 jack_error("too many servers already active");
852 goto fail;
853 case ENOMEM:
854 jack_error("no access to shm registry");
855 goto fail;
858 jack_log("server `%s' registered", server_ptr->name.str);
860 /* clean up shared memory and files from any previous
861 * instance of this server name */
862 jack_cleanup_shm();
863 JackTools::CleanupFiles(server_ptr->name.str);
865 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0)
866 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
868 /* get the engine/driver started */
870 server_ptr->engine = new JackServer(
871 server_ptr->sync.b,
872 server_ptr->temporary.b,
873 server_ptr->client_timeout.i,
874 server_ptr->realtime.b,
875 server_ptr->realtime_priority.i,
876 server_ptr->verbose.b,
877 (jack_timer_type_t)server_ptr->clock_source.ui,
878 server_ptr->name.str);
879 if (server_ptr->engine == NULL)
881 jack_error("Failed to create new JackServer object");
882 goto fail_unregister;
885 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters);
886 if (rc < 0)
888 jack_error("JackServer::Open() failed with %d", rc);
889 goto fail_delete;
892 rc = server_ptr->engine->Start();
893 if (rc < 0)
895 jack_error("JackServer::Start() failed with %d", rc);
896 goto fail_close;
899 return true;
901 fail_close:
902 server_ptr->engine->Close();
904 fail_delete:
905 delete server_ptr->engine;
906 server_ptr->engine = NULL;
908 fail_unregister:
909 jack_log("cleaning up shared memory");
911 jack_cleanup_shm();
913 jack_log("cleaning up files");
915 JackTools::CleanupFiles(server_ptr->name.str);
917 jack_log("unregistering server `%s'", server_ptr->name.str);
919 jack_unregister_server(server_ptr->name.str);
921 fail:
922 return false;
925 EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
927 return driver_ptr->desc_ptr->name;
930 EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
932 return driver_ptr->parameters;
935 EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
937 return driver_ptr->desc_ptr;
940 EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
942 return parameter_ptr->name;
945 EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
947 return parameter_ptr->short_description;
950 EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
952 return parameter_ptr->long_description;
955 EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
957 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0;
960 EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
962 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0;
965 EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
967 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
969 return 0;
972 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
975 EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
977 jack_driver_param_value_t * value_ptr;
978 union jackctl_parameter_value jackctl_value;
980 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
982 switch (parameter_ptr->type)
984 case JackParamInt:
985 jackctl_value.i = value_ptr->i;
986 break;
987 case JackParamUInt:
988 jackctl_value.ui = value_ptr->ui;
989 break;
990 case JackParamChar:
991 jackctl_value.c = value_ptr->c;
992 break;
993 case JackParamString:
994 strcpy(jackctl_value.str, value_ptr->str);
995 break;
996 default:
997 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
998 assert(0);
1001 return jackctl_value;
1004 EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1006 return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc;
1009 EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1011 switch (parameter_ptr->type)
1013 case JackParamInt:
1014 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1015 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1016 return;
1017 case JackParamUInt:
1018 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1019 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1020 return;
1021 default:
1022 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1023 assert(0);
1027 EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1029 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0;
1032 EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1034 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0;
1037 EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1039 return parameter_ptr->type;
1042 EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1044 return parameter_ptr->id;
1047 EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1049 return parameter_ptr->is_set;
1052 EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1054 return *parameter_ptr->value_ptr;
1057 EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1059 if (!parameter_ptr->is_set)
1061 return true;
1064 parameter_ptr->is_set = false;
1066 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1068 return true;
1071 EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1073 bool new_driver_parameter;
1075 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */
1076 if (parameter_ptr->driver_ptr != NULL)
1078 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
1079 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL;
1080 if (new_driver_parameter)
1082 /* jack_info("new driver parameter..."); */
1083 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t));
1084 if (parameter_ptr->driver_parameter_ptr == NULL)
1086 jack_error ("Allocation of jack_driver_param_t structure failed");
1087 return false;
1090 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id;
1091 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1094 switch (parameter_ptr->type)
1096 case JackParamInt:
1097 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i;
1098 break;
1099 case JackParamUInt:
1100 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui;
1101 break;
1102 case JackParamChar:
1103 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c;
1104 break;
1105 case JackParamString:
1106 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str);
1107 break;
1108 case JackParamBool:
1109 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b;
1110 break;
1111 default:
1112 jack_error("unknown parameter type %i", (int)parameter_ptr->type);
1113 assert(0);
1115 if (new_driver_parameter)
1117 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1120 return false;
1124 parameter_ptr->is_set = true;
1125 *parameter_ptr->value_ptr = *value_ptr;
1127 return true;
1130 EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1132 return *parameter_ptr->default_value_ptr;
1135 // Internals clients
1137 EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1139 return server_ptr->internals;
1142 EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1144 return internal_ptr->desc_ptr->name;
1147 EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1149 return internal_ptr->parameters;
1152 EXPORT bool jackctl_server_load_internal(
1153 jackctl_server * server_ptr,
1154 jackctl_internal * internal)
1156 int status;
1157 if (server_ptr->engine != NULL) {
1158 server_ptr->engine->InternalClientLoad(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, &status);
1159 return (internal->refnum > 0);
1160 } else {
1161 return false;
1165 EXPORT bool jackctl_server_unload_internal(
1166 jackctl_server * server_ptr,
1167 jackctl_internal * internal)
1169 int status;
1170 if (server_ptr->engine != NULL && internal->refnum > 0) {
1171 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1172 } else {
1173 return false;
1177 EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1179 if (server_ptr->engine != NULL) {
1180 driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters);
1181 return (driver_ptr->info != 0);
1182 } else {
1183 return false;
1187 EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1189 if (server_ptr->engine != NULL) {
1190 server_ptr->engine->RemoveSlave(driver_ptr->info);
1191 delete driver_ptr->info;
1192 return true;
1193 } else {
1194 return false;
1198 EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1200 if (server_ptr->engine != NULL) {
1201 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0);
1202 } else {
1203 return false;