Correct jackdmp.cpp (failures case were not correct..). Improve JackCoreAudioDriver...
[jack2.git] / common / JackControlAPI.cpp
blob488046c9f578f3e080a1f1277b3d051600fedb4a
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 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
616 constraint_ptr->constraint.range.min.i = min;
617 constraint_ptr->constraint.range.max.i = max;
619 return constraint_ptr;
622 EXPORT jackctl_server_t * jackctl_server_create(
623 bool (* on_device_acquire)(const char * device_name),
624 void (* on_device_release)(const char * device_name))
626 struct jackctl_server * server_ptr;
627 union jackctl_parameter_value value;
629 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
630 if (server_ptr == NULL)
632 jack_error("Cannot allocate memory for jackctl_server structure.");
633 goto fail;
636 server_ptr->drivers = NULL;
637 server_ptr->internals = NULL;
638 server_ptr->parameters = NULL;
639 server_ptr->engine = NULL;
641 strcpy(value.str, JACK_DEFAULT_SERVER_NAME);
642 if (jackctl_add_parameter(
643 &server_ptr->parameters,
644 "name",
645 "Server name to use.",
647 JackParamString,
648 &server_ptr->name,
649 &server_ptr->default_name,
650 value) == NULL)
652 goto fail_free_parameters;
655 value.b = false;
656 if (jackctl_add_parameter(
657 &server_ptr->parameters,
658 "realtime",
659 "Whether to use realtime mode.",
660 "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.",
661 JackParamBool,
662 &server_ptr->realtime,
663 &server_ptr->default_realtime,
664 value) == NULL)
666 goto fail_free_parameters;
669 value.i = 10;
670 if (jackctl_add_parameter(
671 &server_ptr->parameters,
672 "realtime-priority",
673 "Scheduler priority when running in realtime mode.",
675 JackParamInt,
676 &server_ptr->realtime_priority,
677 &server_ptr->default_realtime_priority,
678 value,
679 get_realtime_priority_constraint()) == NULL)
681 goto fail_free_parameters;
684 value.b = false;
685 if (jackctl_add_parameter(
686 &server_ptr->parameters,
687 "temporary",
688 "Exit once all clients have closed their connections.",
690 JackParamBool,
691 &server_ptr->temporary,
692 &server_ptr->default_temporary,
693 value) == NULL)
695 goto fail_free_parameters;
698 value.b = false;
699 if (jackctl_add_parameter(
700 &server_ptr->parameters,
701 "verbose",
702 "Verbose mode.",
704 JackParamBool,
705 &server_ptr->verbose,
706 &server_ptr->default_verbose,
707 value) == NULL)
709 goto fail_free_parameters;
712 value.i = 0;
713 if (jackctl_add_parameter(
714 &server_ptr->parameters,
715 "client-timeout",
716 "Client timeout limit in milliseconds.",
718 JackParamInt,
719 &server_ptr->client_timeout,
720 &server_ptr->default_client_timeout,
721 value) == NULL)
723 goto fail_free_parameters;
726 value.ui = 0;
727 if (jackctl_add_parameter(
728 &server_ptr->parameters,
729 "clock-source",
730 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
732 JackParamUInt,
733 &server_ptr->clock_source,
734 &server_ptr->default_clock_source,
735 value) == NULL)
737 goto fail_free_parameters;
740 value.b = false;
741 if (jackctl_add_parameter(
742 &server_ptr->parameters,
743 "replace-registry",
744 "Replace shared memory registry.",
746 JackParamBool,
747 &server_ptr->replace_registry,
748 &server_ptr->default_replace_registry,
749 value) == NULL)
751 goto fail_free_parameters;
754 value.b = false;
755 if (jackctl_add_parameter(
756 &server_ptr->parameters,
757 "sync",
758 "Use server synchronous mode.",
760 JackParamBool,
761 &server_ptr->sync,
762 &server_ptr->default_sync,
763 value) == NULL)
765 goto fail_free_parameters;
768 JackServerGlobals::on_device_acquire = on_device_acquire;
769 JackServerGlobals::on_device_release = on_device_release;
771 if (!jackctl_drivers_load(server_ptr))
773 goto fail_free_parameters;
776 /* Allowed to fail */
777 jackctl_internals_load(server_ptr);
779 return server_ptr;
781 fail_free_parameters:
782 jackctl_server_free_parameters(server_ptr);
784 free(server_ptr);
786 fail:
787 return NULL;
790 EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
792 jackctl_server_free_drivers(server_ptr);
793 jackctl_server_free_internals(server_ptr);
794 jackctl_server_free_parameters(server_ptr);
795 free(server_ptr);
798 EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
800 return server_ptr->drivers;
803 EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
805 server_ptr->engine->Stop();
806 server_ptr->engine->Close();
807 delete server_ptr->engine;
809 /* clean up shared memory and files from this server instance */
810 jack_log("cleaning up shared memory");
812 jack_cleanup_shm();
814 jack_log("cleaning up files");
816 JackTools::CleanupFiles(server_ptr->name.str);
818 jack_log("unregistering server `%s'", server_ptr->name.str);
820 jack_unregister_server(server_ptr->name.str);
822 server_ptr->engine = NULL;
824 return true;
827 EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
829 return server_ptr->parameters;
832 EXPORT bool
833 jackctl_server_start(
834 jackctl_server *server_ptr,
835 jackctl_driver *driver_ptr)
837 int rc;
839 rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
840 switch (rc)
842 case EEXIST:
843 jack_error("`%s' server already active", server_ptr->name.str);
844 goto fail;
845 case ENOSPC:
846 jack_error("too many servers already active");
847 goto fail;
848 case ENOMEM:
849 jack_error("no access to shm registry");
850 goto fail;
853 jack_log("server `%s' registered", server_ptr->name.str);
855 /* clean up shared memory and files from any previous
856 * instance of this server name */
857 jack_cleanup_shm();
858 JackTools::CleanupFiles(server_ptr->name.str);
860 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0)
861 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
863 /* get the engine/driver started */
865 server_ptr->engine = new JackServer(
866 server_ptr->sync.b,
867 server_ptr->temporary.b,
868 server_ptr->client_timeout.i,
869 server_ptr->realtime.b,
870 server_ptr->realtime_priority.i,
871 server_ptr->verbose.b,
872 (jack_timer_type_t)server_ptr->clock_source.ui,
873 server_ptr->name.str);
874 if (server_ptr->engine == NULL)
876 jack_error("Failed to create new JackServer object");
877 goto fail_unregister;
880 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters);
881 if (rc < 0)
883 jack_error("JackServer::Open() failed with %d", rc);
884 goto fail_delete;
887 rc = server_ptr->engine->Start();
888 if (rc < 0)
890 jack_error("JackServer::Start() failed with %d", rc);
891 goto fail_close;
894 return true;
896 fail_close:
897 server_ptr->engine->Close();
899 fail_delete:
900 delete server_ptr->engine;
901 server_ptr->engine = NULL;
903 fail_unregister:
904 jack_log("cleaning up shared memory");
906 jack_cleanup_shm();
908 jack_log("cleaning up files");
910 JackTools::CleanupFiles(server_ptr->name.str);
912 jack_log("unregistering server `%s'", server_ptr->name.str);
914 jack_unregister_server(server_ptr->name.str);
916 fail:
917 return false;
920 EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
922 return driver_ptr->desc_ptr->name;
925 EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
927 return driver_ptr->parameters;
930 EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
932 return driver_ptr->desc_ptr;
935 EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
937 return parameter_ptr->name;
940 EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
942 return parameter_ptr->short_description;
945 EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
947 return parameter_ptr->long_description;
950 EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
952 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0;
955 EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
957 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0;
960 EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
962 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
964 return 0;
967 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
970 EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
972 jack_driver_param_value_t * value_ptr;
973 union jackctl_parameter_value jackctl_value;
975 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
977 switch (parameter_ptr->type)
979 case JackParamInt:
980 jackctl_value.i = value_ptr->i;
981 break;
982 case JackParamUInt:
983 jackctl_value.ui = value_ptr->ui;
984 break;
985 case JackParamChar:
986 jackctl_value.c = value_ptr->c;
987 break;
988 case JackParamString:
989 strcpy(jackctl_value.str, value_ptr->str);
990 break;
991 default:
992 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
993 assert(0);
996 return jackctl_value;
999 EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1001 return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc;
1004 EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1006 switch (parameter_ptr->type)
1008 case JackParamInt:
1009 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1010 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1011 return;
1012 case JackParamUInt:
1013 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1014 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1015 return;
1016 default:
1017 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1018 assert(0);
1022 EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1024 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0;
1027 EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1029 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0;
1032 EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1034 return parameter_ptr->type;
1037 EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1039 return parameter_ptr->id;
1042 EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1044 return parameter_ptr->is_set;
1047 EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1049 return *parameter_ptr->value_ptr;
1052 EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1054 if (!parameter_ptr->is_set)
1056 return true;
1059 parameter_ptr->is_set = false;
1061 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1063 return true;
1066 EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1068 bool new_driver_parameter;
1070 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */
1071 if (parameter_ptr->driver_ptr != NULL)
1073 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
1074 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL;
1075 if (new_driver_parameter)
1077 /* jack_info("new driver parameter..."); */
1078 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t));
1079 if (parameter_ptr->driver_parameter_ptr == NULL)
1081 jack_error ("Allocation of jack_driver_param_t structure failed");
1082 return false;
1085 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id;
1086 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1089 switch (parameter_ptr->type)
1091 case JackParamInt:
1092 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i;
1093 break;
1094 case JackParamUInt:
1095 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui;
1096 break;
1097 case JackParamChar:
1098 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c;
1099 break;
1100 case JackParamString:
1101 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str);
1102 break;
1103 case JackParamBool:
1104 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b;
1105 break;
1106 default:
1107 jack_error("unknown parameter type %i", (int)parameter_ptr->type);
1108 assert(0);
1110 if (new_driver_parameter)
1112 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1115 return false;
1119 parameter_ptr->is_set = true;
1120 *parameter_ptr->value_ptr = *value_ptr;
1122 return true;
1125 EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1127 return *parameter_ptr->default_value_ptr;
1130 // Internals clients
1132 EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1134 return server_ptr->internals;
1137 EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1139 return internal_ptr->desc_ptr->name;
1142 EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1144 return internal_ptr->parameters;
1147 EXPORT bool jackctl_server_load_internal(
1148 jackctl_server * server_ptr,
1149 jackctl_internal * internal)
1151 int status;
1152 if (server_ptr->engine != NULL) {
1153 server_ptr->engine->InternalClientLoad(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, &status);
1154 return (internal->refnum > 0);
1155 } else {
1156 return false;
1160 EXPORT bool jackctl_server_unload_internal(
1161 jackctl_server * server_ptr,
1162 jackctl_internal * internal)
1164 int status;
1165 if (server_ptr->engine != NULL && internal->refnum > 0) {
1166 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1167 } else {
1168 return false;
1172 EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1174 if (server_ptr->engine != NULL) {
1175 driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters);
1176 return (driver_ptr->info != 0);
1177 } else {
1178 return false;
1182 EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1184 if (server_ptr->engine != NULL) {
1185 server_ptr->engine->RemoveSlave(driver_ptr->info);
1186 delete driver_ptr->info;
1187 return true;
1188 } else {
1189 return false;
1193 EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1195 if (server_ptr->engine != NULL) {
1196 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0);
1197 } else {
1198 return false;