1 // u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */
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.
37 #include "driver_interface.h"
38 #include "JackError.h"
39 #include "JackServer.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"
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
;
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
;
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
;
97 jack_driver_desc_t
* desc_ptr
;
99 JSList
* set_parameters
;
100 JackDriverInfo
* info
;
103 struct jackctl_internal
105 jack_driver_desc_t
* desc_ptr
;
107 JSList
* set_parameters
;
111 struct jackctl_parameter
114 const char * short_description
;
115 const char * long_description
;
116 jackctl_param_type_t type
;
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
;
125 jack_driver_param_t
* driver_parameter_ptr
;
126 jack_driver_param_constraint_desc_t
* constraint_ptr
;
130 struct jackctl_parameter
*
131 jackctl_add_parameter(
132 JSList
** parameters_list_ptr_ptr
,
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.");
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
= ¶meter_ptr
->value
;
162 if (default_value_ptr
== NULL
)
164 default_value_ptr
= ¶meter_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
;
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
;
211 jackctl_add_driver_parameters(
212 struct jackctl_driver
* driver_ptr
)
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
;
230 case JackDriverParamUInt
:
231 jackctl_type
= JackParamUInt
;
232 jackctl_value
.ui
= descriptor_ptr
->value
.ui
;
234 case JackDriverParamChar
:
235 jackctl_type
= JackParamChar
;
236 jackctl_value
.c
= descriptor_ptr
->value
.c
;
238 case JackDriverParamString
:
239 jackctl_type
= JackParamString
;
240 strcpy(jackctl_value
.str
, descriptor_ptr
->value
.str
);
242 case JackDriverParamBool
:
243 jackctl_type
= JackParamBool
;
244 jackctl_value
.b
= descriptor_ptr
->value
.i
;
247 jack_error("unknown driver parameter type %i", (int)descriptor_ptr
->type
);
252 parameter_ptr
= jackctl_add_parameter(
253 &driver_ptr
->parameters
,
254 descriptor_ptr
->name
,
255 descriptor_ptr
->short_desc
,
256 descriptor_ptr
->long_desc
,
261 descriptor_ptr
->constraint
);
263 if (parameter_ptr
== NULL
)
268 parameter_ptr
->driver_ptr
= driver_ptr
;
269 parameter_ptr
->id
= descriptor_ptr
->character
;
275 jackctl_free_driver_parameters(driver_ptr
);
281 jackctl_drivers_load(
282 struct jackctl_server
* server_ptr
)
284 struct jackctl_driver
* driver_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!");
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.");
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
);
315 server_ptr
->drivers
= jack_slist_append(server_ptr
->drivers
, driver_ptr
);
318 node_ptr
= descriptor_node_ptr
;
319 descriptor_node_ptr
= descriptor_node_ptr
->next
;
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
);
344 free(server_ptr
->drivers
);
345 server_ptr
->drivers
= next_node_ptr
;
350 jackctl_internals_load(
351 struct jackctl_server
* server_ptr
)
353 struct jackctl_internal
* internal_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!");
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.");
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
);
384 server_ptr
->internals
= jack_slist_append(server_ptr
->internals
, internal_ptr
);
387 node_ptr
= descriptor_node_ptr
;
388 descriptor_node_ptr
= descriptor_node_ptr
->next
;
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
);
413 free(server_ptr
->internals
);
414 server_ptr
->internals
= next_node_ptr
;
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
;
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
);
446 jackctl_setup_signals(
449 if ((waitEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
)) == NULL
) {
450 jack_error("CreateEvent fails err = %ld", GetLastError());
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());
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
479 snprintf (buf
, sizeof(buf
), "received signal %d during shutdown (ignored)\n", sig
);
483 jackctl_setup_signals(
488 struct sigaction action
;
491 /* ensure that we are in our own process group so that
492 kill (SIG, -pgrp) does the right thing.
497 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
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
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);
561 jackctl_wait_signals(sigset_t signals
)
567 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
570 sigwait(&signals
, &sig
);
572 fprintf(stderr
, "jack main caught signal %d\n", sig
);
576 //jack_dump_configuration(engine, 1);
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);
600 jack_driver_param_constraint_desc_t
*
601 get_realtime_priority_constraint()
603 jack_driver_param_constraint_desc_t
* constraint_ptr
;
606 if (!jack_get_thread_realtime_priority_range(&min
, &max
))
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.");
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.");
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
,
650 "Server name to use.",
654 &server_ptr
->default_name
,
657 goto fail_free_parameters
;
661 if (jackctl_add_parameter(
662 &server_ptr
->parameters
,
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.",
667 &server_ptr
->realtime
,
668 &server_ptr
->default_realtime
,
671 goto fail_free_parameters
;
675 if (jackctl_add_parameter(
676 &server_ptr
->parameters
,
678 "Scheduler priority when running in realtime mode.",
681 &server_ptr
->realtime_priority
,
682 &server_ptr
->default_realtime_priority
,
684 get_realtime_priority_constraint()) == NULL
)
686 goto fail_free_parameters
;
690 if (jackctl_add_parameter(
691 &server_ptr
->parameters
,
693 "Exit once all clients have closed their connections.",
696 &server_ptr
->temporary
,
697 &server_ptr
->default_temporary
,
700 goto fail_free_parameters
;
704 if (jackctl_add_parameter(
705 &server_ptr
->parameters
,
710 &server_ptr
->verbose
,
711 &server_ptr
->default_verbose
,
714 goto fail_free_parameters
;
718 if (jackctl_add_parameter(
719 &server_ptr
->parameters
,
721 "Client timeout limit in milliseconds.",
724 &server_ptr
->client_timeout
,
725 &server_ptr
->default_client_timeout
,
728 goto fail_free_parameters
;
732 if (jackctl_add_parameter(
733 &server_ptr
->parameters
,
735 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
738 &server_ptr
->clock_source
,
739 &server_ptr
->default_clock_source
,
742 goto fail_free_parameters
;
746 if (jackctl_add_parameter(
747 &server_ptr
->parameters
,
749 "Replace shared memory registry.",
752 &server_ptr
->replace_registry
,
753 &server_ptr
->default_replace_registry
,
756 goto fail_free_parameters
;
760 if (jackctl_add_parameter(
761 &server_ptr
->parameters
,
763 "Use server synchronous mode.",
767 &server_ptr
->default_sync
,
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
);
786 fail_free_parameters
:
787 jackctl_server_free_parameters(server_ptr
);
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
);
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");
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
;
832 EXPORT
const JSList
* jackctl_server_get_parameters(jackctl_server
*server_ptr
)
834 return server_ptr
->parameters
;
838 jackctl_server_start(
839 jackctl_server
*server_ptr
,
840 jackctl_driver
*driver_ptr
)
844 rc
= jack_register_server(server_ptr
->name
.str
, server_ptr
->replace_registry
.b
);
848 jack_error("`%s' server already active", server_ptr
->name
.str
);
851 jack_error("too many servers already active");
854 jack_error("no access to shm registry");
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 */
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(
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
);
888 jack_error("JackServer::Open() failed with %d", rc
);
892 rc
= server_ptr
->engine
->Start();
895 jack_error("JackServer::Start() failed with %d", rc
);
902 server_ptr
->engine
->Close();
905 delete server_ptr
->engine
;
906 server_ptr
->engine
= NULL
;
909 jack_log("cleaning up shared memory");
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
);
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
))
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
= ¶meter_ptr
->constraint_ptr
->constraint
.enumeration
.possible_values_array
[index
].value
;
982 switch (parameter_ptr
->type
)
985 jackctl_value
.i
= value_ptr
->i
;
988 jackctl_value
.ui
= value_ptr
->ui
;
991 jackctl_value
.c
= value_ptr
->c
;
993 case JackParamString
:
994 strcpy(jackctl_value
.str
, value_ptr
->str
);
997 jack_error("bad driver parameter type %i (enum constraint)", (int)parameter_ptr
->type
);
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
)
1014 min_ptr
->i
= parameter_ptr
->constraint_ptr
->constraint
.range
.min
.i
;
1015 max_ptr
->i
= parameter_ptr
->constraint_ptr
->constraint
.range
.max
.i
;
1018 min_ptr
->ui
= parameter_ptr
->constraint_ptr
->constraint
.range
.min
.ui
;
1019 max_ptr
->ui
= parameter_ptr
->constraint_ptr
->constraint
.range
.max
.ui
;
1022 jack_error("bad driver parameter type %i (range constraint)", (int)parameter_ptr
->type
);
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
)
1064 parameter_ptr
->is_set
= false;
1066 *parameter_ptr
->value_ptr
= *parameter_ptr
->default_value_ptr
;
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");
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
)
1097 parameter_ptr
->driver_parameter_ptr
->value
.i
= value_ptr
->i
;
1100 parameter_ptr
->driver_parameter_ptr
->value
.ui
= value_ptr
->ui
;
1103 parameter_ptr
->driver_parameter_ptr
->value
.c
= value_ptr
->c
;
1105 case JackParamString
:
1106 strcpy(parameter_ptr
->driver_parameter_ptr
->value
.str
, value_ptr
->str
);
1109 parameter_ptr
->driver_parameter_ptr
->value
.i
= value_ptr
->b
;
1112 jack_error("unknown parameter type %i", (int)parameter_ptr
->type
);
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
);
1124 parameter_ptr
->is_set
= true;
1125 *parameter_ptr
->value_ptr
= *value_ptr
;
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
)
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);
1165 EXPORT
bool jackctl_server_unload_internal(
1166 jackctl_server
* server_ptr
,
1167 jackctl_internal
* internal
)
1170 if (server_ptr
->engine
!= NULL
&& internal
->refnum
> 0) {
1171 return ((server_ptr
->engine
->GetEngine()->InternalClientUnload(internal
->refnum
, &status
)) == 0);
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);
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
;
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);