Init engine fields, cleanup.
[jack2.git] / common / JackControlAPI.cpp
blobcd0ec2bf36c5ed21905b1979f2bce19f61320c26
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 /* uint32_t, max port number */
87 union jackctl_parameter_value port_max;
88 union jackctl_parameter_value default_port_max;
90 /* bool */
91 union jackctl_parameter_value replace_registry;
92 union jackctl_parameter_value default_replace_registry;
94 /* bool, synchronous or asynchronous engine mode */
95 union jackctl_parameter_value sync;
96 union jackctl_parameter_value default_sync;
99 struct jackctl_driver
101 jack_driver_desc_t * desc_ptr;
102 JSList * parameters;
103 JSList * set_parameters;
104 JackDriverInfo* info;
107 struct jackctl_internal
109 jack_driver_desc_t * desc_ptr;
110 JSList * parameters;
111 JSList * set_parameters;
112 int refnum;
115 struct jackctl_parameter
117 const char * name;
118 const char * short_description;
119 const char * long_description;
120 jackctl_param_type_t type;
121 bool is_set;
122 union jackctl_parameter_value * value_ptr;
123 union jackctl_parameter_value * default_value_ptr;
125 union jackctl_parameter_value value;
126 union jackctl_parameter_value default_value;
127 struct jackctl_driver * driver_ptr;
128 char id;
129 jack_driver_param_t * driver_parameter_ptr;
130 jack_driver_param_constraint_desc_t * constraint_ptr;
133 static
134 struct jackctl_parameter *
135 jackctl_add_parameter(
136 JSList ** parameters_list_ptr_ptr,
137 const char * name,
138 const char * short_description,
139 const char * long_description,
140 jackctl_param_type_t type,
141 union jackctl_parameter_value * value_ptr,
142 union jackctl_parameter_value * default_value_ptr,
143 union jackctl_parameter_value value,
144 jack_driver_param_constraint_desc_t * constraint_ptr = NULL)
146 struct jackctl_parameter * parameter_ptr;
148 parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter));
149 if (parameter_ptr == NULL)
151 jack_error("Cannot allocate memory for jackctl_parameter structure.");
152 goto fail;
155 parameter_ptr->name = name;
156 parameter_ptr->short_description = short_description;
157 parameter_ptr->long_description = long_description;
158 parameter_ptr->type = type;
159 parameter_ptr->is_set = false;
161 if (value_ptr == NULL)
163 value_ptr = &parameter_ptr->value;
166 if (default_value_ptr == NULL)
168 default_value_ptr = &parameter_ptr->default_value;
171 parameter_ptr->value_ptr = value_ptr;
172 parameter_ptr->default_value_ptr = default_value_ptr;
174 *value_ptr = *default_value_ptr = value;
176 parameter_ptr->driver_ptr = NULL;
177 parameter_ptr->driver_parameter_ptr = NULL;
178 parameter_ptr->id = 0;
179 parameter_ptr->constraint_ptr = constraint_ptr;
181 *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
183 return parameter_ptr;
185 fail:
186 return NULL;
189 static
190 void
191 jackctl_free_driver_parameters(
192 struct jackctl_driver * driver_ptr)
194 JSList * next_node_ptr;
196 while (driver_ptr->parameters)
198 next_node_ptr = driver_ptr->parameters->next;
199 free(driver_ptr->parameters->data);
200 free(driver_ptr->parameters);
201 driver_ptr->parameters = next_node_ptr;
204 while (driver_ptr->set_parameters)
206 next_node_ptr = driver_ptr->set_parameters->next;
207 free(driver_ptr->set_parameters->data);
208 free(driver_ptr->set_parameters);
209 driver_ptr->set_parameters = next_node_ptr;
213 static
214 bool
215 jackctl_add_driver_parameters(
216 struct jackctl_driver * driver_ptr)
218 uint32_t i;
219 union jackctl_parameter_value jackctl_value;
220 jackctl_param_type_t jackctl_type;
221 struct jackctl_parameter * parameter_ptr;
222 jack_driver_param_desc_t * descriptor_ptr;
224 for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
226 descriptor_ptr = driver_ptr->desc_ptr->params + i;
228 switch (descriptor_ptr->type)
230 case JackDriverParamInt:
231 jackctl_type = JackParamInt;
232 jackctl_value.i = descriptor_ptr->value.i;
233 break;
234 case JackDriverParamUInt:
235 jackctl_type = JackParamUInt;
236 jackctl_value.ui = descriptor_ptr->value.ui;
237 break;
238 case JackDriverParamChar:
239 jackctl_type = JackParamChar;
240 jackctl_value.c = descriptor_ptr->value.c;
241 break;
242 case JackDriverParamString:
243 jackctl_type = JackParamString;
244 strcpy(jackctl_value.str, descriptor_ptr->value.str);
245 break;
246 case JackDriverParamBool:
247 jackctl_type = JackParamBool;
248 jackctl_value.b = descriptor_ptr->value.i;
249 break;
250 default:
251 jack_error("unknown driver parameter type %i", (int)descriptor_ptr->type);
252 assert(0);
253 goto fail;
256 parameter_ptr = jackctl_add_parameter(
257 &driver_ptr->parameters,
258 descriptor_ptr->name,
259 descriptor_ptr->short_desc,
260 descriptor_ptr->long_desc,
261 jackctl_type,
262 NULL,
263 NULL,
264 jackctl_value,
265 descriptor_ptr->constraint);
267 if (parameter_ptr == NULL)
269 goto fail;
272 parameter_ptr->driver_ptr = driver_ptr;
273 parameter_ptr->id = descriptor_ptr->character;
276 return true;
278 fail:
279 jackctl_free_driver_parameters(driver_ptr);
281 return false;
284 static int
285 jackctl_drivers_load(
286 struct jackctl_server * server_ptr)
288 struct jackctl_driver * driver_ptr;
289 JSList *node_ptr;
290 JSList *descriptor_node_ptr;
292 descriptor_node_ptr = jack_drivers_load(NULL);
293 if (descriptor_node_ptr == NULL)
295 jack_error("could not find any drivers in driver directory!");
296 return false;
299 while (descriptor_node_ptr != NULL)
301 driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver));
302 if (driver_ptr == NULL)
304 jack_error("memory allocation of jackctl_driver structure failed.");
305 goto next;
308 driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
309 driver_ptr->parameters = NULL;
310 driver_ptr->set_parameters = NULL;
312 if (!jackctl_add_driver_parameters(driver_ptr))
314 assert(driver_ptr->parameters == NULL);
315 free(driver_ptr);
316 goto next;
319 server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
321 next:
322 node_ptr = descriptor_node_ptr;
323 descriptor_node_ptr = descriptor_node_ptr->next;
324 free(node_ptr);
327 return true;
330 static
331 void
332 jackctl_server_free_drivers(
333 struct jackctl_server * server_ptr)
335 JSList * next_node_ptr;
336 struct jackctl_driver * driver_ptr;
338 while (server_ptr->drivers)
340 next_node_ptr = server_ptr->drivers->next;
341 driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
343 jackctl_free_driver_parameters(driver_ptr);
344 free(driver_ptr->desc_ptr->params);
345 free(driver_ptr->desc_ptr);
346 free(driver_ptr);
348 free(server_ptr->drivers);
349 server_ptr->drivers = next_node_ptr;
353 static int
354 jackctl_internals_load(
355 struct jackctl_server * server_ptr)
357 struct jackctl_internal * internal_ptr;
358 JSList *node_ptr;
359 JSList *descriptor_node_ptr;
361 descriptor_node_ptr = jack_internals_load(NULL);
362 if (descriptor_node_ptr == NULL)
364 jack_error("could not find any internals in driver directory!");
365 return false;
368 while (descriptor_node_ptr != NULL)
370 internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal));
371 if (internal_ptr == NULL)
373 jack_error("memory allocation of jackctl_driver structure failed.");
374 goto next;
377 internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
378 internal_ptr->parameters = NULL;
379 internal_ptr->set_parameters = NULL;
381 if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr))
383 assert(internal_ptr->parameters == NULL);
384 free(internal_ptr);
385 goto next;
388 server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr);
390 next:
391 node_ptr = descriptor_node_ptr;
392 descriptor_node_ptr = descriptor_node_ptr->next;
393 free(node_ptr);
396 return true;
399 static
400 void
401 jackctl_server_free_internals(
402 struct jackctl_server * server_ptr)
404 JSList * next_node_ptr;
405 struct jackctl_internal * internal_ptr;
407 while (server_ptr->internals)
409 next_node_ptr = server_ptr->internals->next;
410 internal_ptr = (struct jackctl_internal *)server_ptr->internals->data;
412 jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr);
413 free(internal_ptr->desc_ptr->params);
414 free(internal_ptr->desc_ptr);
415 free(internal_ptr);
417 free(server_ptr->internals);
418 server_ptr->internals = next_node_ptr;
422 static
423 void
424 jackctl_server_free_parameters(
425 struct jackctl_server * server_ptr)
427 JSList * next_node_ptr;
429 while (server_ptr->parameters)
431 next_node_ptr = server_ptr->parameters->next;
432 free(server_ptr->parameters->data);
433 free(server_ptr->parameters);
434 server_ptr->parameters = next_node_ptr;
438 #ifdef WIN32
440 static HANDLE waitEvent;
442 static void do_nothing_handler(int signum)
444 printf("jack main caught signal %d\n", signum);
445 (void) signal(SIGINT, SIG_DFL);
446 SetEvent(waitEvent);
449 sigset_t
450 jackctl_setup_signals(
451 unsigned int flags)
453 if ((waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
454 jack_error("CreateEvent fails err = %ld", GetLastError());
455 return 0;
458 (void) signal(SIGINT, do_nothing_handler);
459 (void) signal(SIGABRT, do_nothing_handler);
460 (void) signal(SIGTERM, do_nothing_handler);
462 return (sigset_t)waitEvent;
465 void jackctl_wait_signals(sigset_t signals)
467 if (WaitForSingleObject(waitEvent, INFINITE) != WAIT_OBJECT_0) {
468 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
472 #else
474 static
475 void
476 do_nothing_handler(int sig)
478 /* this is used by the child (active) process, but it never
479 gets called unless we are already shutting down after
480 another signal.
482 char buf[64];
483 snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig);
486 EXPORT sigset_t
487 jackctl_setup_signals(
488 unsigned int flags)
490 sigset_t signals;
491 sigset_t allsignals;
492 struct sigaction action;
493 int i;
495 /* ensure that we are in our own process group so that
496 kill (SIG, -pgrp) does the right thing.
499 setsid();
501 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
503 /* what's this for?
505 POSIX says that signals are delivered like this:
507 * if a thread has blocked that signal, it is not
508 a candidate to receive the signal.
509 * of all threads not blocking the signal, pick
510 one at random, and deliver the signal.
512 this means that a simple-minded multi-threaded program can
513 expect to get POSIX signals delivered randomly to any one
514 of its threads,
516 here, we block all signals that we think we might receive
517 and want to catch. all "child" threads will inherit this
518 setting. if we create a thread that calls sigwait() on the
519 same set of signals, implicitly unblocking all those
520 signals. any of those signals that are delivered to the
521 process will be delivered to that thread, and that thread
522 alone. this makes cleanup for a signal-driven exit much
523 easier, since we know which thread is doing it and more
524 importantly, we are free to call async-unsafe functions,
525 because the code is executing in normal thread context
526 after a return from sigwait().
529 sigemptyset(&signals);
530 sigaddset(&signals, SIGHUP);
531 sigaddset(&signals, SIGINT);
532 sigaddset(&signals, SIGQUIT);
533 sigaddset(&signals, SIGPIPE);
534 sigaddset(&signals, SIGTERM);
535 sigaddset(&signals, SIGUSR1);
536 sigaddset(&signals, SIGUSR2);
538 /* all child threads will inherit this mask unless they
539 * explicitly reset it
542 pthread_sigmask(SIG_BLOCK, &signals, 0);
544 /* install a do-nothing handler because otherwise pthreads
545 behaviour is undefined when we enter sigwait.
548 sigfillset(&allsignals);
549 action.sa_handler = do_nothing_handler;
550 action.sa_mask = allsignals;
551 action.sa_flags = SA_RESTART|SA_RESETHAND;
553 for (i = 1; i < NSIG; i++)
555 if (sigismember (&signals, i))
557 sigaction(i, &action, 0);
561 return signals;
564 EXPORT void
565 jackctl_wait_signals(sigset_t signals)
567 int sig;
568 bool waiting = true;
570 while (waiting) {
571 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
572 sigwait(&signals);
573 #else
574 sigwait(&signals, &sig);
575 #endif
576 fprintf(stderr, "jack main caught signal %d\n", sig);
578 switch (sig) {
579 case SIGUSR1:
580 //jack_dump_configuration(engine, 1);
581 break;
582 case SIGUSR2:
583 // driver exit
584 waiting = false;
585 break;
586 case SIGTTOU:
587 break;
588 default:
589 waiting = false;
590 break;
594 if (sig != SIGSEGV) {
595 // unblock signals so we can see them during shutdown.
596 // this will help prod developers not to lose sight of
597 // bugs that cause segfaults etc. during shutdown.
598 sigprocmask(SIG_UNBLOCK, &signals, 0);
601 #endif
603 static
604 jack_driver_param_constraint_desc_t *
605 get_realtime_priority_constraint()
607 jack_driver_param_constraint_desc_t * constraint_ptr;
608 int min, max;
610 if (!jack_get_thread_realtime_priority_range(&min, &max))
612 return NULL;
615 //jack_info("realtime priority range is (%d,%d)", min, max);
617 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
618 if (constraint_ptr == NULL)
620 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
621 return NULL;
623 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
625 constraint_ptr->constraint.range.min.i = min;
626 constraint_ptr->constraint.range.max.i = max;
628 return constraint_ptr;
631 EXPORT jackctl_server_t * jackctl_server_create(
632 bool (* on_device_acquire)(const char * device_name),
633 void (* on_device_release)(const char * device_name))
635 struct jackctl_server * server_ptr;
636 union jackctl_parameter_value value;
638 server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
639 if (server_ptr == NULL)
641 jack_error("Cannot allocate memory for jackctl_server structure.");
642 goto fail;
645 server_ptr->drivers = NULL;
646 server_ptr->internals = NULL;
647 server_ptr->parameters = NULL;
648 server_ptr->engine = NULL;
650 strcpy(value.str, JACK_DEFAULT_SERVER_NAME);
651 if (jackctl_add_parameter(
652 &server_ptr->parameters,
653 "name",
654 "Server name to use.",
656 JackParamString,
657 &server_ptr->name,
658 &server_ptr->default_name,
659 value) == NULL)
661 goto fail_free_parameters;
664 value.b = false;
665 if (jackctl_add_parameter(
666 &server_ptr->parameters,
667 "realtime",
668 "Whether to use realtime mode.",
669 "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.",
670 JackParamBool,
671 &server_ptr->realtime,
672 &server_ptr->default_realtime,
673 value) == NULL)
675 goto fail_free_parameters;
678 value.i = 10;
679 if (jackctl_add_parameter(
680 &server_ptr->parameters,
681 "realtime-priority",
682 "Scheduler priority when running in realtime mode.",
684 JackParamInt,
685 &server_ptr->realtime_priority,
686 &server_ptr->default_realtime_priority,
687 value,
688 get_realtime_priority_constraint()) == NULL)
690 goto fail_free_parameters;
693 value.b = false;
694 if (jackctl_add_parameter(
695 &server_ptr->parameters,
696 "temporary",
697 "Exit once all clients have closed their connections.",
699 JackParamBool,
700 &server_ptr->temporary,
701 &server_ptr->default_temporary,
702 value) == NULL)
704 goto fail_free_parameters;
707 value.b = false;
708 if (jackctl_add_parameter(
709 &server_ptr->parameters,
710 "verbose",
711 "Verbose mode.",
713 JackParamBool,
714 &server_ptr->verbose,
715 &server_ptr->default_verbose,
716 value) == NULL)
718 goto fail_free_parameters;
721 value.i = 0;
722 if (jackctl_add_parameter(
723 &server_ptr->parameters,
724 "client-timeout",
725 "Client timeout limit in milliseconds.",
727 JackParamInt,
728 &server_ptr->client_timeout,
729 &server_ptr->default_client_timeout,
730 value) == NULL)
732 goto fail_free_parameters;
735 value.ui = 0;
736 if (jackctl_add_parameter(
737 &server_ptr->parameters,
738 "clock-source",
739 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
741 JackParamUInt,
742 &server_ptr->clock_source,
743 &server_ptr->default_clock_source,
744 value) == NULL)
746 goto fail_free_parameters;
749 value.ui = PORT_NUM;
750 if (jackctl_add_parameter(
751 &server_ptr->parameters,
752 "port-max",
753 "Maximum number of ports.",
755 JackParamUInt,
756 &server_ptr->port_max,
757 &server_ptr->default_port_max,
758 value) == NULL)
760 goto fail_free_parameters;
763 value.b = false;
764 if (jackctl_add_parameter(
765 &server_ptr->parameters,
766 "replace-registry",
767 "Replace shared memory registry.",
769 JackParamBool,
770 &server_ptr->replace_registry,
771 &server_ptr->default_replace_registry,
772 value) == NULL)
774 goto fail_free_parameters;
777 value.b = false;
778 if (jackctl_add_parameter(
779 &server_ptr->parameters,
780 "sync",
781 "Use server synchronous mode.",
783 JackParamBool,
784 &server_ptr->sync,
785 &server_ptr->default_sync,
786 value) == NULL)
788 goto fail_free_parameters;
791 JackServerGlobals::on_device_acquire = on_device_acquire;
792 JackServerGlobals::on_device_release = on_device_release;
794 if (!jackctl_drivers_load(server_ptr))
796 goto fail_free_parameters;
799 /* Allowed to fail */
800 jackctl_internals_load(server_ptr);
802 return server_ptr;
804 fail_free_parameters:
805 jackctl_server_free_parameters(server_ptr);
807 free(server_ptr);
809 fail:
810 return NULL;
813 EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
815 jackctl_server_free_drivers(server_ptr);
816 jackctl_server_free_internals(server_ptr);
817 jackctl_server_free_parameters(server_ptr);
818 free(server_ptr);
821 EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
823 return server_ptr->drivers;
826 EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
828 server_ptr->engine->Stop();
829 server_ptr->engine->Close();
830 delete server_ptr->engine;
832 /* clean up shared memory and files from this server instance */
833 jack_log("cleaning up shared memory");
835 jack_cleanup_shm();
837 jack_log("cleaning up files");
839 JackTools::CleanupFiles(server_ptr->name.str);
841 jack_log("unregistering server `%s'", server_ptr->name.str);
843 jack_unregister_server(server_ptr->name.str);
845 server_ptr->engine = NULL;
847 return true;
850 EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
852 return server_ptr->parameters;
855 EXPORT bool
856 jackctl_server_start(
857 jackctl_server *server_ptr,
858 jackctl_driver *driver_ptr)
860 int rc;
862 rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
863 switch (rc)
865 case EEXIST:
866 jack_error("`%s' server already active", server_ptr->name.str);
867 goto fail;
868 case ENOSPC:
869 jack_error("too many servers already active");
870 goto fail;
871 case ENOMEM:
872 jack_error("no access to shm registry");
873 goto fail;
876 jack_log("server `%s' registered", server_ptr->name.str);
878 /* clean up shared memory and files from any previous
879 * instance of this server name */
880 jack_cleanup_shm();
881 JackTools::CleanupFiles(server_ptr->name.str);
883 if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0)
884 server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
886 /* check port max value before allocating server */
887 if (server_ptr->port_max.ui > PORT_NUM_MAX) {
888 jack_error("JACK server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX);
889 goto fail;
892 /* get the engine/driver started */
893 server_ptr->engine = new JackServer(
894 server_ptr->sync.b,
895 server_ptr->temporary.b,
896 server_ptr->client_timeout.i,
897 server_ptr->realtime.b,
898 server_ptr->realtime_priority.i,
899 server_ptr->port_max.ui,
900 server_ptr->verbose.b,
901 (jack_timer_type_t)server_ptr->clock_source.ui,
902 server_ptr->name.str);
903 if (server_ptr->engine == NULL)
905 jack_error("Failed to create new JackServer object");
906 goto fail_unregister;
909 rc = server_ptr->engine->Open(driver_ptr->desc_ptr, driver_ptr->set_parameters);
910 if (rc < 0)
912 jack_error("JackServer::Open() failed with %d", rc);
913 goto fail_delete;
916 rc = server_ptr->engine->Start();
917 if (rc < 0)
919 jack_error("JackServer::Start() failed with %d", rc);
920 goto fail_close;
923 return true;
925 fail_close:
926 server_ptr->engine->Close();
928 fail_delete:
929 delete server_ptr->engine;
930 server_ptr->engine = NULL;
932 fail_unregister:
933 jack_log("cleaning up shared memory");
935 jack_cleanup_shm();
937 jack_log("cleaning up files");
939 JackTools::CleanupFiles(server_ptr->name.str);
941 jack_log("unregistering server `%s'", server_ptr->name.str);
943 jack_unregister_server(server_ptr->name.str);
945 fail:
946 return false;
949 EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
951 return driver_ptr->desc_ptr->name;
954 EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
956 return driver_ptr->parameters;
959 EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
961 return driver_ptr->desc_ptr;
964 EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
966 return parameter_ptr->name;
969 EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
971 return parameter_ptr->short_description;
974 EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
976 return parameter_ptr->long_description;
979 EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
981 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0;
984 EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
986 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0;
989 EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
991 if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
993 return 0;
996 return parameter_ptr->constraint_ptr->constraint.enumeration.count;
999 EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
1001 jack_driver_param_value_t * value_ptr;
1002 union jackctl_parameter_value jackctl_value;
1004 value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1006 switch (parameter_ptr->type)
1008 case JackParamInt:
1009 jackctl_value.i = value_ptr->i;
1010 break;
1011 case JackParamUInt:
1012 jackctl_value.ui = value_ptr->ui;
1013 break;
1014 case JackParamChar:
1015 jackctl_value.c = value_ptr->c;
1016 break;
1017 case JackParamString:
1018 strcpy(jackctl_value.str, value_ptr->str);
1019 break;
1020 default:
1021 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1022 assert(0);
1025 return jackctl_value;
1028 EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1030 return parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc;
1033 EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1035 switch (parameter_ptr->type)
1037 case JackParamInt:
1038 min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1039 max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1040 return;
1041 case JackParamUInt:
1042 min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1043 max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1044 return;
1045 default:
1046 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1047 assert(0);
1051 EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t * parameter_ptr)
1053 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0;
1056 EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t * parameter_ptr)
1058 return parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0;
1061 EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1063 return parameter_ptr->type;
1066 EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1068 return parameter_ptr->id;
1071 EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1073 return parameter_ptr->is_set;
1076 EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
1078 return *parameter_ptr->value_ptr;
1081 EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1083 if (!parameter_ptr->is_set)
1085 return true;
1088 parameter_ptr->is_set = false;
1090 *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1092 return true;
1095 EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1097 bool new_driver_parameter;
1099 /* for driver parameters, set the parameter by adding jack_driver_param_t in the set_parameters list */
1100 if (parameter_ptr->driver_ptr != NULL)
1102 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
1103 new_driver_parameter = parameter_ptr->driver_parameter_ptr == NULL;
1104 if (new_driver_parameter)
1106 /* jack_info("new driver parameter..."); */
1107 parameter_ptr->driver_parameter_ptr = (jack_driver_param_t *)malloc(sizeof(jack_driver_param_t));
1108 if (parameter_ptr->driver_parameter_ptr == NULL)
1110 jack_error ("Allocation of jack_driver_param_t structure failed");
1111 return false;
1114 parameter_ptr->driver_parameter_ptr->character = parameter_ptr->id;
1115 parameter_ptr->driver_ptr->set_parameters = jack_slist_append(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1118 switch (parameter_ptr->type)
1120 case JackParamInt:
1121 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->i;
1122 break;
1123 case JackParamUInt:
1124 parameter_ptr->driver_parameter_ptr->value.ui = value_ptr->ui;
1125 break;
1126 case JackParamChar:
1127 parameter_ptr->driver_parameter_ptr->value.c = value_ptr->c;
1128 break;
1129 case JackParamString:
1130 strcpy(parameter_ptr->driver_parameter_ptr->value.str, value_ptr->str);
1131 break;
1132 case JackParamBool:
1133 parameter_ptr->driver_parameter_ptr->value.i = value_ptr->b;
1134 break;
1135 default:
1136 jack_error("unknown parameter type %i", (int)parameter_ptr->type);
1137 assert(0);
1139 if (new_driver_parameter)
1141 parameter_ptr->driver_ptr->set_parameters = jack_slist_remove(parameter_ptr->driver_ptr->set_parameters, parameter_ptr->driver_parameter_ptr);
1144 return false;
1148 parameter_ptr->is_set = true;
1149 *parameter_ptr->value_ptr = *value_ptr;
1151 return true;
1154 EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
1156 return *parameter_ptr->default_value_ptr;
1159 // Internals clients
1161 EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1163 return server_ptr->internals;
1166 EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1168 return internal_ptr->desc_ptr->name;
1171 EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1173 return internal_ptr->parameters;
1176 EXPORT bool jackctl_server_load_internal(
1177 jackctl_server * server_ptr,
1178 jackctl_internal * internal)
1180 int status;
1181 if (server_ptr->engine != NULL) {
1182 server_ptr->engine->InternalClientLoad(internal->desc_ptr->name, internal->desc_ptr->name, internal->set_parameters, JackNullOption, &internal->refnum, -1, &status);
1183 return (internal->refnum > 0);
1184 } else {
1185 return false;
1189 EXPORT bool jackctl_server_unload_internal(
1190 jackctl_server * server_ptr,
1191 jackctl_internal * internal)
1193 int status;
1194 if (server_ptr->engine != NULL && internal->refnum > 0) {
1195 return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1196 } else {
1197 return false;
1201 EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1203 if (server_ptr->engine != NULL) {
1204 driver_ptr->info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, driver_ptr->set_parameters);
1205 return (driver_ptr->info != 0);
1206 } else {
1207 return false;
1211 EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1213 if (server_ptr->engine != NULL) {
1214 server_ptr->engine->RemoveSlave(driver_ptr->info);
1215 delete driver_ptr->info;
1216 return true;
1217 } else {
1218 return false;
1222 EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1224 if (server_ptr->engine != NULL) {
1225 return (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, driver_ptr->set_parameters) == 0);
1226 } else {
1227 return false;