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"
50 /* JackEngine::CheckPortsConnect() has some assumptions about char values */
51 static struct jack_constraint_enum_char_descriptor self_connect_mode_constraint_descr_array
[] =
53 { ' ', "Don't restrict self connect requests" },
54 { 'E', "Fail self connect requests to external ports only" },
55 { 'e', "Ignore self connect requests to external ports only" },
56 { 'A', "Fail all self connect requests" },
57 { 'a', "Ignore all self connect requests" },
67 class JackServer
* engine
;
69 /* string, server name */
70 union jackctl_parameter_value name
;
71 union jackctl_parameter_value default_name
;
73 /* bool, whether to be "realtime" */
74 union jackctl_parameter_value realtime
;
75 union jackctl_parameter_value default_realtime
;
78 union jackctl_parameter_value realtime_priority
;
79 union jackctl_parameter_value default_realtime_priority
;
81 /* bool, whether to exit once all clients have closed their connections */
82 union jackctl_parameter_value temporary
;
83 union jackctl_parameter_value default_temporary
;
85 /* bool, whether to be verbose */
86 union jackctl_parameter_value verbose
;
87 union jackctl_parameter_value default_verbose
;
89 /* int32_t, msecs; if zero, use period size. */
90 union jackctl_parameter_value client_timeout
;
91 union jackctl_parameter_value default_client_timeout
;
93 /* uint32_t, clock source type */
94 union jackctl_parameter_value clock_source
;
95 union jackctl_parameter_value default_clock_source
;
97 /* uint32_t, max port number */
98 union jackctl_parameter_value port_max
;
99 union jackctl_parameter_value default_port_max
;
102 union jackctl_parameter_value replace_registry
;
103 union jackctl_parameter_value default_replace_registry
;
105 /* bool, synchronous or asynchronous engine mode */
106 union jackctl_parameter_value sync
;
107 union jackctl_parameter_value default_sync
;
109 /* char enum, self connect mode mode */
110 union jackctl_parameter_value self_connect_mode
;
111 union jackctl_parameter_value default_self_connect_mode
;
114 struct jackctl_driver
116 jack_driver_desc_t
* desc_ptr
;
121 struct jackctl_internal
123 jack_driver_desc_t
* desc_ptr
;
128 struct jackctl_parameter
131 const char * short_description
;
132 const char * long_description
;
133 jackctl_param_type_t type
;
135 union jackctl_parameter_value
* value_ptr
;
136 union jackctl_parameter_value
* default_value_ptr
;
138 union jackctl_parameter_value value
;
139 union jackctl_parameter_value default_value
;
140 struct jackctl_driver
* driver_ptr
;
142 jack_driver_param_constraint_desc_t
* constraint_ptr
;
145 const char * jack_get_self_connect_mode_description(char mode
)
147 struct jack_constraint_enum_char_descriptor
* descr_ptr
;
149 for (descr_ptr
= self_connect_mode_constraint_descr_array
;
152 if (descr_ptr
->value
== mode
) return descr_ptr
->short_desc
;
158 struct jackctl_parameter
*
159 jackctl_add_parameter(
160 JSList
** parameters_list_ptr_ptr
,
162 const char * short_description
,
163 const char * long_description
,
164 jackctl_param_type_t type
,
165 union jackctl_parameter_value
* value_ptr
,
166 union jackctl_parameter_value
* default_value_ptr
,
167 union jackctl_parameter_value value
,
168 jack_driver_param_constraint_desc_t
* constraint_ptr
= NULL
)
170 struct jackctl_parameter
* parameter_ptr
;
172 parameter_ptr
= (struct jackctl_parameter
*)malloc(sizeof(struct jackctl_parameter
));
173 if (parameter_ptr
== NULL
)
175 jack_error("Cannot allocate memory for jackctl_parameter structure.");
179 parameter_ptr
->name
= name
;
180 parameter_ptr
->short_description
= short_description
;
181 parameter_ptr
->long_description
= long_description
;
182 parameter_ptr
->type
= type
;
183 parameter_ptr
->is_set
= false;
185 if (value_ptr
== NULL
)
187 value_ptr
= ¶meter_ptr
->value
;
190 if (default_value_ptr
== NULL
)
192 default_value_ptr
= ¶meter_ptr
->default_value
;
195 parameter_ptr
->value_ptr
= value_ptr
;
196 parameter_ptr
->default_value_ptr
= default_value_ptr
;
198 *value_ptr
= *default_value_ptr
= value
;
200 parameter_ptr
->driver_ptr
= NULL
;
201 parameter_ptr
->id
= 0;
202 parameter_ptr
->constraint_ptr
= constraint_ptr
;
204 *parameters_list_ptr_ptr
= jack_slist_append(*parameters_list_ptr_ptr
, parameter_ptr
);
206 return parameter_ptr
;
214 jackctl_free_driver_parameters(
215 struct jackctl_driver
* driver_ptr
)
217 JSList
* next_node_ptr
;
219 while (driver_ptr
->parameters
)
221 next_node_ptr
= driver_ptr
->parameters
->next
;
222 jack_constraint_free(((jackctl_parameter
*)driver_ptr
->parameters
->data
)->constraint_ptr
);
223 free(driver_ptr
->parameters
->data
);
224 free(driver_ptr
->parameters
);
225 driver_ptr
->parameters
= next_node_ptr
;
231 jackctl_add_driver_parameters(
232 struct jackctl_driver
* driver_ptr
)
236 union jackctl_parameter_value jackctl_value
;
237 jackctl_param_type_t jackctl_type
;
238 struct jackctl_parameter
* parameter_ptr
;
239 jack_driver_param_desc_t
* descriptor_ptr
;
241 for (i
= 0 ; i
< driver_ptr
->desc_ptr
->nparams
; i
++)
243 descriptor_ptr
= driver_ptr
->desc_ptr
->params
+ i
;
245 switch (descriptor_ptr
->type
)
247 case JackDriverParamInt
:
248 jackctl_type
= JackParamInt
;
249 jackctl_value
.i
= descriptor_ptr
->value
.i
;
251 case JackDriverParamUInt
:
252 jackctl_type
= JackParamUInt
;
253 jackctl_value
.ui
= descriptor_ptr
->value
.ui
;
255 case JackDriverParamChar
:
256 jackctl_type
= JackParamChar
;
257 jackctl_value
.c
= descriptor_ptr
->value
.c
;
259 case JackDriverParamString
:
260 jackctl_type
= JackParamString
;
261 strcpy(jackctl_value
.str
, descriptor_ptr
->value
.str
);
263 case JackDriverParamBool
:
264 jackctl_type
= JackParamBool
;
265 jackctl_value
.b
= descriptor_ptr
->value
.i
;
268 jack_error("Unknown driver parameter type %i", (int)descriptor_ptr
->type
);
273 parameter_ptr
= jackctl_add_parameter(
274 &driver_ptr
->parameters
,
275 descriptor_ptr
->name
,
276 descriptor_ptr
->short_desc
,
277 descriptor_ptr
->long_desc
,
282 descriptor_ptr
->constraint
);
284 if (parameter_ptr
== NULL
)
289 parameter_ptr
->driver_ptr
= driver_ptr
;
290 parameter_ptr
->id
= descriptor_ptr
->character
;
296 jackctl_free_driver_parameters(driver_ptr
);
301 /* destroy jack_driver_param_desc_t list created by jackctl_create_param_list() */
303 jackctl_destroy_param_list(
317 /* for drivers and internals are configured through jack_driver_param_t JSList */
318 /* this function creates such list from a jackctl_parameter list */
321 jackctl_create_param_list(
322 const JSList
* paramlist
,
323 JSList
** retparamlist
)
325 jackctl_parameter
* param_ptr
;
326 jack_driver_param_t
* retparam_ptr
;
328 *retparamlist
= NULL
;
329 while (paramlist
!= NULL
)
331 param_ptr
= (jackctl_parameter
*)paramlist
->data
;
332 if (param_ptr
->is_set
)
334 /* jack_info("setting driver parameter %p ...", parameter_ptr); */
335 retparam_ptr
= (jack_driver_param_t
*)malloc(sizeof(jack_driver_param_t
));
336 if (retparam_ptr
== NULL
)
338 jack_error ("Allocation of jack_driver_param_t structure failed");
342 retparam_ptr
->character
= param_ptr
->id
;
344 switch (param_ptr
->type
)
347 retparam_ptr
->value
.i
= param_ptr
->value_ptr
->i
;
350 retparam_ptr
->value
.ui
= param_ptr
->value_ptr
->ui
;
353 retparam_ptr
->value
.c
= param_ptr
->value_ptr
->c
;
355 case JackParamString
:
356 strcpy(retparam_ptr
->value
.str
, param_ptr
->value_ptr
->str
);
359 retparam_ptr
->value
.i
= param_ptr
->value_ptr
->b
;
362 jack_error("Unknown parameter type %i", (int)param_ptr
->type
);
367 *retparamlist
= jack_slist_append(*retparamlist
, retparam_ptr
);
370 paramlist
= paramlist
->next
;
378 jackctl_destroy_param_list(*retparamlist
);
383 jackctl_drivers_load(
384 struct jackctl_server
* server_ptr
)
386 struct jackctl_driver
* driver_ptr
;
388 JSList
*descriptor_node_ptr
;
390 descriptor_node_ptr
= jack_drivers_load(NULL
);
391 if (descriptor_node_ptr
== NULL
)
393 jack_error("Could not find any drivers in driver directory!");
397 while (descriptor_node_ptr
!= NULL
)
399 driver_ptr
= (struct jackctl_driver
*)malloc(sizeof(struct jackctl_driver
));
400 if (driver_ptr
== NULL
)
402 jack_error("Memory allocation of jackctl_driver structure failed.");
406 driver_ptr
->desc_ptr
= (jack_driver_desc_t
*)descriptor_node_ptr
->data
;
407 driver_ptr
->parameters
= NULL
;
408 driver_ptr
->infos
= NULL
;
410 if (!jackctl_add_driver_parameters(driver_ptr
))
412 assert(driver_ptr
->parameters
== NULL
);
417 server_ptr
->drivers
= jack_slist_append(server_ptr
->drivers
, driver_ptr
);
420 node_ptr
= descriptor_node_ptr
;
421 descriptor_node_ptr
= descriptor_node_ptr
->next
;
430 jackctl_server_free_drivers(
431 struct jackctl_server
* server_ptr
)
433 JSList
* next_node_ptr
;
434 struct jackctl_driver
* driver_ptr
;
436 while (server_ptr
->drivers
)
438 next_node_ptr
= server_ptr
->drivers
->next
;
439 driver_ptr
= (struct jackctl_driver
*)server_ptr
->drivers
->data
;
441 jackctl_free_driver_parameters(driver_ptr
);
442 free(driver_ptr
->desc_ptr
->params
);
443 free(driver_ptr
->desc_ptr
);
446 free(server_ptr
->drivers
);
447 server_ptr
->drivers
= next_node_ptr
;
452 jackctl_internals_load(
453 struct jackctl_server
* server_ptr
)
455 struct jackctl_internal
* internal_ptr
;
457 JSList
*descriptor_node_ptr
;
459 descriptor_node_ptr
= jack_internals_load(NULL
);
460 if (descriptor_node_ptr
== NULL
)
462 jack_error("Could not find any internals in driver directory!");
466 while (descriptor_node_ptr
!= NULL
)
468 internal_ptr
= (struct jackctl_internal
*)malloc(sizeof(struct jackctl_internal
));
469 if (internal_ptr
== NULL
)
471 jack_error("Memory allocation of jackctl_driver structure failed.");
475 internal_ptr
->desc_ptr
= (jack_driver_desc_t
*)descriptor_node_ptr
->data
;
476 internal_ptr
->parameters
= NULL
;
477 internal_ptr
->refnum
= -1;
479 if (!jackctl_add_driver_parameters((struct jackctl_driver
*)internal_ptr
))
481 assert(internal_ptr
->parameters
== NULL
);
486 server_ptr
->internals
= jack_slist_append(server_ptr
->internals
, internal_ptr
);
489 node_ptr
= descriptor_node_ptr
;
490 descriptor_node_ptr
= descriptor_node_ptr
->next
;
499 jackctl_server_free_internals(
500 struct jackctl_server
* server_ptr
)
502 JSList
* next_node_ptr
;
503 struct jackctl_internal
* internal_ptr
;
505 while (server_ptr
->internals
)
507 next_node_ptr
= server_ptr
->internals
->next
;
508 internal_ptr
= (struct jackctl_internal
*)server_ptr
->internals
->data
;
510 jackctl_free_driver_parameters((struct jackctl_driver
*)internal_ptr
);
511 free(internal_ptr
->desc_ptr
->params
);
512 free(internal_ptr
->desc_ptr
);
515 free(server_ptr
->internals
);
516 server_ptr
->internals
= next_node_ptr
;
522 jackctl_server_free_parameters(
523 struct jackctl_server
* server_ptr
)
525 JSList
* next_node_ptr
;
527 while (server_ptr
->parameters
)
529 next_node_ptr
= server_ptr
->parameters
->next
;
530 jack_constraint_free(((jackctl_parameter
*)server_ptr
->parameters
->data
)->constraint_ptr
);
531 free(server_ptr
->parameters
->data
);
532 free(server_ptr
->parameters
);
533 server_ptr
->parameters
= next_node_ptr
;
539 struct jackctl_sigmask
544 static jackctl_sigmask sigmask
;
546 static void signal_handler(int signum
)
548 printf("Jack main caught signal %d\n", signum
);
549 (void) signal(SIGINT
, SIG_DFL
);
550 SetEvent(sigmask
.wait_event
);
554 jackctl_setup_signals(
557 if ((sigmask
.wait_event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
)) == NULL
) {
558 jack_error("CreateEvent fails err = %ld", GetLastError());
562 (void) signal(SIGINT
, signal_handler
);
563 (void) signal(SIGABRT
, signal_handler
);
564 (void) signal(SIGTERM
, signal_handler
);
569 void jackctl_wait_signals(jackctl_sigmask_t
* signals
)
571 if (WaitForSingleObject(signals
->wait_event
, INFINITE
) != WAIT_OBJECT_0
) {
572 jack_error("WaitForSingleObject fails err = %ld", GetLastError());
578 struct jackctl_sigmask
583 static jackctl_sigmask sigmask
;
587 signal_handler(int sig
)
589 /* this is used by the child (active) process, but it never
590 gets called unless we are already shutting down after
594 snprintf(buf
, sizeof(buf
), "Received signal %d during shutdown (ignored)\n", sig
);
597 SERVER_EXPORT jackctl_sigmask_t
*
598 jackctl_setup_signals(
602 struct sigaction action
;
605 /* ensure that we are in our own process group so that
606 kill (SIG, -pgrp) does the right thing.
611 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
615 POSIX says that signals are delivered like this:
617 * if a thread has blocked that signal, it is not
618 a candidate to receive the signal.
619 * of all threads not blocking the signal, pick
620 one at random, and deliver the signal.
622 this means that a simple-minded multi-threaded program can
623 expect to get POSIX signals delivered randomly to any one
626 here, we block all signals that we think we might receive
627 and want to catch. all "child" threads will inherit this
628 setting. if we create a thread that calls sigwait() on the
629 same set of signals, implicitly unblocking all those
630 signals. any of those signals that are delivered to the
631 process will be delivered to that thread, and that thread
632 alone. this makes cleanup for a signal-driven exit much
633 easier, since we know which thread is doing it and more
634 importantly, we are free to call async-unsafe functions,
635 because the code is executing in normal thread context
636 after a return from sigwait().
639 sigemptyset(&sigmask
.signals
);
640 sigaddset(&sigmask
.signals
, SIGHUP
);
641 sigaddset(&sigmask
.signals
, SIGINT
);
642 sigaddset(&sigmask
.signals
, SIGQUIT
);
643 sigaddset(&sigmask
.signals
, SIGPIPE
);
644 sigaddset(&sigmask
.signals
, SIGTERM
);
646 /* android's bionic c doesn't provide pthread_cancel() and related functions.
647 * to solve this issue, use pthread_kill() & SIGUSR1 instead.
649 sigaddset(&sigmask
.signals
, SIGUSR1
);
651 sigaddset(&sigmask
.signals
, SIGUSR2
);
653 /* all child threads will inherit this mask unless they
654 * explicitly reset it
657 pthread_sigmask(SIG_BLOCK
, &sigmask
.signals
, 0);
659 /* install a do-nothing handler because otherwise pthreads
660 behaviour is undefined when we enter sigwait.
663 sigfillset(&allsignals
);
664 action
.sa_handler
= signal_handler
;
665 action
.sa_mask
= allsignals
;
666 action
.sa_flags
= SA_RESTART
|SA_RESETHAND
;
668 for (i
= 1; i
< NSIG
; i
++)
670 if (sigismember (&sigmask
.signals
, i
))
672 sigaction(i
, &action
, 0);
680 jackctl_wait_signals(jackctl_sigmask_t
* sigmask
)
686 #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
687 sigwait(&sigmask
->signals
);
689 sigwait(&sigmask
->signals
, &sig
);
691 fprintf(stderr
, "Jack main caught signal %d\n", sig
);
695 //jack_dump_configuration(engine, 1);
709 if (sig
!= SIGSEGV
) {
710 // unblock signals so we can see them during shutdown.
711 // this will help prod developers not to lose sight of
712 // bugs that cause segfaults etc. during shutdown.
713 sigprocmask(SIG_UNBLOCK
, &sigmask
->signals
, 0);
719 jack_driver_param_constraint_desc_t
*
720 get_realtime_priority_constraint()
722 jack_driver_param_constraint_desc_t
* constraint_ptr
;
725 if (!jack_get_thread_realtime_priority_range(&min
, &max
))
730 //jack_info("realtime priority range is (%d,%d)", min, max);
732 constraint_ptr
= (jack_driver_param_constraint_desc_t
*)calloc(1, sizeof(jack_driver_param_constraint_desc_t
));
733 if (constraint_ptr
== NULL
)
735 jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
738 constraint_ptr
->flags
= JACK_CONSTRAINT_FLAG_RANGE
;
740 constraint_ptr
->constraint
.range
.min
.i
= min
;
741 constraint_ptr
->constraint
.range
.max
.i
= max
;
743 return constraint_ptr
;
746 SERVER_EXPORT jackctl_server_t
* jackctl_server_create(
747 bool (* on_device_acquire
)(const char * device_name
),
748 void (* on_device_release
)(const char * device_name
))
750 return jackctl_server_create2(on_device_acquire
, on_device_release
, NULL
);
753 SERVER_EXPORT jackctl_server_t
* jackctl_server_create2(
754 bool (* on_device_acquire
)(const char * device_name
),
755 void (* on_device_release
)(const char * device_name
),
756 void (* on_device_reservation_loop
)(void))
758 struct jackctl_server
* server_ptr
;
759 union jackctl_parameter_value value
;
761 server_ptr
= (struct jackctl_server
*)malloc(sizeof(struct jackctl_server
));
762 if (server_ptr
== NULL
)
764 jack_error("Cannot allocate memory for jackctl_server structure.");
768 server_ptr
->drivers
= NULL
;
769 server_ptr
->internals
= NULL
;
770 server_ptr
->parameters
= NULL
;
771 server_ptr
->engine
= NULL
;
773 strcpy(value
.str
, JackTools::DefaultServerName());
774 if (jackctl_add_parameter(
775 &server_ptr
->parameters
,
777 "Server name to use.",
781 &server_ptr
->default_name
,
784 goto fail_free_parameters
;
788 if (jackctl_add_parameter(
789 &server_ptr
->parameters
,
791 "Whether to use realtime mode.",
792 "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.",
794 &server_ptr
->realtime
,
795 &server_ptr
->default_realtime
,
798 goto fail_free_parameters
;
802 if (jackctl_add_parameter(
803 &server_ptr
->parameters
,
805 "Scheduler priority when running in realtime mode.",
808 &server_ptr
->realtime_priority
,
809 &server_ptr
->default_realtime_priority
,
811 get_realtime_priority_constraint()) == NULL
)
813 goto fail_free_parameters
;
817 if (jackctl_add_parameter(
818 &server_ptr
->parameters
,
820 "Exit once all clients have closed their connections.",
823 &server_ptr
->temporary
,
824 &server_ptr
->default_temporary
,
827 goto fail_free_parameters
;
831 if (jackctl_add_parameter(
832 &server_ptr
->parameters
,
837 &server_ptr
->verbose
,
838 &server_ptr
->default_verbose
,
841 goto fail_free_parameters
;
845 if (jackctl_add_parameter(
846 &server_ptr
->parameters
,
848 "Client timeout limit in milliseconds.",
851 &server_ptr
->client_timeout
,
852 &server_ptr
->default_client_timeout
,
855 goto fail_free_parameters
;
859 if (jackctl_add_parameter(
860 &server_ptr
->parameters
,
862 "Clocksource type : c(ycle) | h(pet) | s(ystem).",
865 &server_ptr
->clock_source
,
866 &server_ptr
->default_clock_source
,
869 goto fail_free_parameters
;
873 if (jackctl_add_parameter(
874 &server_ptr
->parameters
,
876 "Maximum number of ports.",
879 &server_ptr
->port_max
,
880 &server_ptr
->default_port_max
,
883 goto fail_free_parameters
;
887 if (jackctl_add_parameter(
888 &server_ptr
->parameters
,
890 "Replace shared memory registry.",
893 &server_ptr
->replace_registry
,
894 &server_ptr
->default_replace_registry
,
897 goto fail_free_parameters
;
901 if (jackctl_add_parameter(
902 &server_ptr
->parameters
,
904 "Use server synchronous mode.",
908 &server_ptr
->default_sync
,
911 goto fail_free_parameters
;
914 value
.c
= JACK_DEFAULT_SELF_CONNECT_MODE
;
915 if (jackctl_add_parameter(
916 &server_ptr
->parameters
,
918 "Self connect mode.",
919 "Whether JACK clients are allowed to connect their own ports",
921 &server_ptr
->self_connect_mode
,
922 &server_ptr
->default_self_connect_mode
,
924 jack_constraint_compose_enum_char(
925 JACK_CONSTRAINT_FLAG_STRICT
| JACK_CONSTRAINT_FLAG_FAKE_VALUE
,
926 self_connect_mode_constraint_descr_array
)) == NULL
)
928 goto fail_free_parameters
;
931 JackServerGlobals::on_device_acquire
= on_device_acquire
;
932 JackServerGlobals::on_device_release
= on_device_release
;
933 JackServerGlobals::on_device_reservation_loop
= on_device_reservation_loop
;
935 if (!jackctl_drivers_load(server_ptr
))
937 goto fail_free_parameters
;
940 /* Allowed to fail */
941 jackctl_internals_load(server_ptr
);
945 fail_free_parameters
:
946 jackctl_server_free_parameters(server_ptr
);
954 SERVER_EXPORT
void jackctl_server_destroy(jackctl_server
*server_ptr
)
957 jackctl_server_free_drivers(server_ptr
);
958 jackctl_server_free_internals(server_ptr
);
959 jackctl_server_free_parameters(server_ptr
);
964 SERVER_EXPORT
const JSList
* jackctl_server_get_drivers_list(jackctl_server
*server_ptr
)
966 return (server_ptr
) ? server_ptr
->drivers
: NULL
;
969 SERVER_EXPORT
bool jackctl_server_stop(jackctl_server
*server_ptr
)
972 server_ptr
->engine
->Stop();
979 SERVER_EXPORT
bool jackctl_server_close(jackctl_server
*server_ptr
)
982 server_ptr
->engine
->Close();
983 delete server_ptr
->engine
;
985 /* clean up shared memory and files from this server instance */
986 jack_log("Cleaning up shared memory");
990 jack_log("Cleaning up files");
992 JackTools::CleanupFiles(server_ptr
->name
.str
);
994 jack_log("Unregistering server `%s'", server_ptr
->name
.str
);
996 jack_unregister_server(server_ptr
->name
.str
);
998 server_ptr
->engine
= NULL
;
1006 SERVER_EXPORT
const JSList
* jackctl_server_get_parameters(jackctl_server
*server_ptr
)
1008 return (server_ptr
) ? server_ptr
->parameters
: NULL
;
1012 jackctl_server_open(
1013 jackctl_server
*server_ptr
,
1014 jackctl_driver
*driver_ptr
)
1016 JSList
* paramlist
= NULL
;
1020 if (!server_ptr
|| !driver_ptr
) {
1024 int rc
= jack_register_server(server_ptr
->name
.str
, server_ptr
->replace_registry
.b
);
1028 jack_error("`%s' server already active", server_ptr
->name
.str
);
1031 jack_error("Too many servers already active");
1034 jack_error("No access to shm registry");
1038 jack_log("Server `%s' registered", server_ptr
->name
.str
);
1040 /* clean up shared memory and files from any previous
1041 * instance of this server name */
1043 JackTools::CleanupFiles(server_ptr
->name
.str
);
1045 if (!server_ptr
->realtime
.b
&& server_ptr
->client_timeout
.i
== 0) {
1046 server_ptr
->client_timeout
.i
= 500; /* 0.5 sec; usable when non realtime. */
1049 /* check port max value before allocating server */
1050 if (server_ptr
->port_max
.ui
> PORT_NUM_MAX
) {
1051 jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr
->port_max
.ui
, PORT_NUM_MAX
);
1055 /* get the engine/driver started */
1056 server_ptr
->engine
= new JackServer(
1058 server_ptr
->temporary
.b
,
1059 server_ptr
->client_timeout
.i
,
1060 server_ptr
->realtime
.b
,
1061 server_ptr
->realtime_priority
.i
,
1062 server_ptr
->port_max
.ui
,
1063 server_ptr
->verbose
.b
,
1064 (jack_timer_type_t
)server_ptr
->clock_source
.ui
,
1065 server_ptr
->self_connect_mode
.c
,
1066 server_ptr
->name
.str
);
1067 if (server_ptr
->engine
== NULL
)
1069 jack_error("Failed to create new JackServer object");
1070 goto fail_unregister
;
1073 if (!jackctl_create_param_list(driver_ptr
->parameters
, ¶mlist
)) goto fail_delete
;
1074 rc
= server_ptr
->engine
->Open(driver_ptr
->desc_ptr
, paramlist
);
1075 jackctl_destroy_param_list(paramlist
);
1078 jack_error("JackServer::Open failed with %d", rc
);
1084 } catch (std::exception
&) {
1085 jack_error("jackctl_server_open error...");
1086 jackctl_destroy_param_list(paramlist
);
1090 delete server_ptr
->engine
;
1091 server_ptr
->engine
= NULL
;
1094 jack_log("Cleaning up shared memory");
1098 jack_log("Cleaning up files");
1100 JackTools::CleanupFiles(server_ptr
->name
.str
);
1102 jack_log("Unregistering server `%s'", server_ptr
->name
.str
);
1104 jack_unregister_server(server_ptr
->name
.str
);
1111 jackctl_server_start(
1112 jackctl_server
*server_ptr
)
1117 int rc
= server_ptr
->engine
->Start();
1118 bool result
= rc
>= 0;
1121 jack_error("JackServer::Start() failed with %d", rc
);
1127 SERVER_EXPORT
const char * jackctl_driver_get_name(jackctl_driver
*driver_ptr
)
1129 return (driver_ptr
) ? driver_ptr
->desc_ptr
->name
: NULL
;
1132 SERVER_EXPORT jackctl_driver_type_t
jackctl_driver_get_type(jackctl_driver
*driver_ptr
)
1134 return (driver_ptr
) ? (jackctl_driver_type_t
)driver_ptr
->desc_ptr
->type
: (jackctl_driver_type_t
)0;
1137 SERVER_EXPORT
const JSList
* jackctl_driver_get_parameters(jackctl_driver
*driver_ptr
)
1139 return (driver_ptr
) ? driver_ptr
->parameters
: NULL
;
1142 SERVER_EXPORT jack_driver_desc_t
* jackctl_driver_get_desc(jackctl_driver
*driver_ptr
)
1144 return (driver_ptr
) ? driver_ptr
->desc_ptr
: NULL
;
1147 SERVER_EXPORT
const char * jackctl_parameter_get_name(jackctl_parameter
*parameter_ptr
)
1149 return (parameter_ptr
) ? parameter_ptr
->name
: NULL
;
1152 SERVER_EXPORT
const char * jackctl_parameter_get_short_description(jackctl_parameter
*parameter_ptr
)
1154 return (parameter_ptr
) ? parameter_ptr
->short_description
: NULL
;
1157 SERVER_EXPORT
const char * jackctl_parameter_get_long_description(jackctl_parameter
*parameter_ptr
)
1159 return (parameter_ptr
) ? parameter_ptr
->long_description
: NULL
;
1162 SERVER_EXPORT
bool jackctl_parameter_has_range_constraint(jackctl_parameter
*parameter_ptr
)
1164 return (parameter_ptr
) ? (parameter_ptr
->constraint_ptr
!= NULL
&& (parameter_ptr
->constraint_ptr
->flags
& JACK_CONSTRAINT_FLAG_RANGE
) != 0) : false;
1167 SERVER_EXPORT
bool jackctl_parameter_has_enum_constraint(jackctl_parameter
*parameter_ptr
)
1169 return (parameter_ptr
) ? (parameter_ptr
->constraint_ptr
!= NULL
&& (parameter_ptr
->constraint_ptr
->flags
& JACK_CONSTRAINT_FLAG_RANGE
) == 0): false;
1172 SERVER_EXPORT
uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter
*parameter_ptr
)
1174 if (!parameter_ptr
) {
1178 if (!jackctl_parameter_has_enum_constraint(parameter_ptr
))
1183 return parameter_ptr
->constraint_ptr
->constraint
.enumeration
.count
;
1186 SERVER_EXPORT
union jackctl_parameter_value
jackctl_parameter_get_enum_constraint_value(jackctl_parameter
*parameter_ptr
, uint32_t index
)
1188 jack_driver_param_value_t
* value_ptr
;
1189 union jackctl_parameter_value jackctl_value
;
1191 if (!parameter_ptr
) {
1192 memset(&jackctl_value
, 0, sizeof(jackctl_value
));
1193 return jackctl_value
;
1196 value_ptr
= ¶meter_ptr
->constraint_ptr
->constraint
.enumeration
.possible_values_array
[index
].value
;
1198 switch (parameter_ptr
->type
)
1201 jackctl_value
.i
= value_ptr
->i
;
1204 jackctl_value
.ui
= value_ptr
->ui
;
1207 jackctl_value
.c
= value_ptr
->c
;
1209 case JackParamString
:
1210 strcpy(jackctl_value
.str
, value_ptr
->str
);
1213 jack_error("Bad driver parameter type %i (enum constraint)", (int)parameter_ptr
->type
);
1217 return jackctl_value
;
1220 SERVER_EXPORT
const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter
*parameter_ptr
, uint32_t index
)
1222 return (parameter_ptr
) ? parameter_ptr
->constraint_ptr
->constraint
.enumeration
.possible_values_array
[index
].short_desc
: NULL
;
1225 SERVER_EXPORT
void jackctl_parameter_get_range_constraint(jackctl_parameter
*parameter_ptr
, union jackctl_parameter_value
* min_ptr
, union jackctl_parameter_value
* max_ptr
)
1227 if (!parameter_ptr
|| !min_ptr
|| !max_ptr
) {
1231 switch (parameter_ptr
->type
)
1234 min_ptr
->i
= parameter_ptr
->constraint_ptr
->constraint
.range
.min
.i
;
1235 max_ptr
->i
= parameter_ptr
->constraint_ptr
->constraint
.range
.max
.i
;
1238 min_ptr
->ui
= parameter_ptr
->constraint_ptr
->constraint
.range
.min
.ui
;
1239 max_ptr
->ui
= parameter_ptr
->constraint_ptr
->constraint
.range
.max
.ui
;
1242 jack_error("Bad driver parameter type %i (range constraint)", (int)parameter_ptr
->type
);
1247 SERVER_EXPORT
bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t
* parameter_ptr
)
1249 return (parameter_ptr
) ? (parameter_ptr
->constraint_ptr
!= NULL
&& (parameter_ptr
->constraint_ptr
->flags
& JACK_CONSTRAINT_FLAG_STRICT
) != 0) : false;
1252 SERVER_EXPORT
bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t
* parameter_ptr
)
1254 return (parameter_ptr
) ? (parameter_ptr
->constraint_ptr
!= NULL
&& (parameter_ptr
->constraint_ptr
->flags
& JACK_CONSTRAINT_FLAG_FAKE_VALUE
) != 0) : false;
1257 SERVER_EXPORT jackctl_param_type_t
jackctl_parameter_get_type(jackctl_parameter
*parameter_ptr
)
1259 return (parameter_ptr
) ? parameter_ptr
->type
: (jackctl_param_type_t
)0;
1262 SERVER_EXPORT
char jackctl_parameter_get_id(jackctl_parameter_t
* parameter_ptr
)
1264 return (parameter_ptr
) ? parameter_ptr
->id
: 0;
1267 SERVER_EXPORT
bool jackctl_parameter_is_set(jackctl_parameter
*parameter_ptr
)
1269 return (parameter_ptr
) ? parameter_ptr
->is_set
: false;
1272 SERVER_EXPORT
union jackctl_parameter_value
jackctl_parameter_get_value(jackctl_parameter
*parameter_ptr
)
1274 if (parameter_ptr
) {
1275 return *parameter_ptr
->value_ptr
;
1277 union jackctl_parameter_value jackctl_value
;
1278 memset(&jackctl_value
, 0, sizeof(jackctl_value
));
1279 return jackctl_value
;
1283 SERVER_EXPORT
bool jackctl_parameter_reset(jackctl_parameter
*parameter_ptr
)
1285 if (!parameter_ptr
) {
1289 if (!parameter_ptr
->is_set
)
1294 parameter_ptr
->is_set
= false;
1296 *parameter_ptr
->value_ptr
= *parameter_ptr
->default_value_ptr
;
1301 SERVER_EXPORT
bool jackctl_parameter_set_value(jackctl_parameter
*parameter_ptr
, const union jackctl_parameter_value
* value_ptr
)
1303 if (!parameter_ptr
|| !value_ptr
) {
1307 parameter_ptr
->is_set
= true;
1308 *parameter_ptr
->value_ptr
= *value_ptr
;
1313 SERVER_EXPORT
union jackctl_parameter_value
jackctl_parameter_get_default_value(jackctl_parameter
*parameter_ptr
)
1315 if (parameter_ptr
) {
1316 return *parameter_ptr
->default_value_ptr
;
1318 union jackctl_parameter_value jackctl_value
;
1319 memset(&jackctl_value
, 0, sizeof(jackctl_value
));
1320 return jackctl_value
;
1324 // Internals clients
1326 SERVER_EXPORT
const JSList
* jackctl_server_get_internals_list(jackctl_server
*server_ptr
)
1328 return (server_ptr
) ? server_ptr
->internals
: NULL
;
1331 SERVER_EXPORT
const char * jackctl_internal_get_name(jackctl_internal
*internal_ptr
)
1333 return (internal_ptr
) ? internal_ptr
->desc_ptr
->name
: NULL
;
1336 SERVER_EXPORT
const JSList
* jackctl_internal_get_parameters(jackctl_internal
*internal_ptr
)
1338 return (internal_ptr
) ? internal_ptr
->parameters
: NULL
;
1341 SERVER_EXPORT
bool jackctl_server_load_internal(
1342 jackctl_server
* server_ptr
,
1343 jackctl_internal
* internal
)
1345 if (!server_ptr
|| !internal
) {
1350 if (server_ptr
->engine
!= NULL
) {
1352 if (!jackctl_create_param_list(internal
->parameters
, ¶mlist
)) return false;
1353 server_ptr
->engine
->InternalClientLoad2(internal
->desc_ptr
->name
, internal
->desc_ptr
->name
, paramlist
, JackNullOption
, &internal
->refnum
, -1, &status
);
1354 jackctl_destroy_param_list(paramlist
);
1355 return (internal
->refnum
> 0);
1361 SERVER_EXPORT
bool jackctl_server_unload_internal(
1362 jackctl_server
* server_ptr
,
1363 jackctl_internal
* internal
)
1365 if (!server_ptr
|| !internal
) {
1370 if (server_ptr
->engine
!= NULL
&& internal
->refnum
> 0) {
1371 // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
1372 return ((server_ptr
->engine
->GetEngine()->InternalClientUnload(internal
->refnum
, &status
)) == 0);
1378 SERVER_EXPORT
bool jackctl_server_load_session_file(
1379 jackctl_server
* server_ptr
,
1382 if (!server_ptr
|| !file
|| !server_ptr
->engine
) {
1386 return (server_ptr
->engine
->LoadInternalSessionFile(file
) >= 0);
1389 SERVER_EXPORT
bool jackctl_server_add_slave(jackctl_server
* server_ptr
, jackctl_driver
* driver_ptr
)
1391 if (server_ptr
&& server_ptr
->engine
) {
1392 if (server_ptr
->engine
->IsRunning()) {
1393 jack_error("Cannot add a slave in a running server");
1397 if (!jackctl_create_param_list(driver_ptr
->parameters
, ¶mlist
)) return false;
1398 JackDriverInfo
* info
= server_ptr
->engine
->AddSlave(driver_ptr
->desc_ptr
, paramlist
);
1399 jackctl_destroy_param_list(paramlist
);
1401 driver_ptr
->infos
= jack_slist_append(driver_ptr
->infos
, info
);
1412 SERVER_EXPORT
bool jackctl_server_remove_slave(jackctl_server
* server_ptr
, jackctl_driver
* driver_ptr
)
1414 if (server_ptr
&& server_ptr
->engine
) {
1415 if (server_ptr
->engine
->IsRunning()) {
1416 jack_error("Cannot remove a slave from a running server");
1419 if (driver_ptr
->infos
) {
1420 JackDriverInfo
* info
= (JackDriverInfo
*)driver_ptr
->infos
->data
;
1422 driver_ptr
->infos
= jack_slist_remove(driver_ptr
->infos
, info
);
1423 server_ptr
->engine
->RemoveSlave(info
);
1435 SERVER_EXPORT
bool jackctl_server_switch_master(jackctl_server
* server_ptr
, jackctl_driver
* driver_ptr
)
1437 if (server_ptr
&& server_ptr
->engine
) {
1439 if (!jackctl_create_param_list(driver_ptr
->parameters
, ¶mlist
)) return false;
1440 bool ret
= (server_ptr
->engine
->SwitchMaster(driver_ptr
->desc_ptr
, paramlist
) == 0);
1441 jackctl_destroy_param_list(paramlist
);