Jack2  1.9.10
JackControlAPI.cpp
1 // u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */
2 /*
3  JACK control API implementation
4 
5  Copyright (C) 2008 Nedko Arnaudov
6  Copyright (C) 2008 Grame
7 
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.
11 
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.
16 
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.
20 
21 */
22 
23 #ifndef WIN32
24 #include <stdint.h>
25 #include <dirent.h>
26 #include <pthread.h>
27 #endif
28 
29 #include "types.h"
30 #include <string.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <assert.h>
34 #include <signal.h>
35 #include <sys/utsname.h>
36 
37 #include "jslist.h"
38 #include "driver_interface.h"
39 #include "JackError.h"
40 #include "JackServer.h"
41 #include "shm.h"
42 #include "JackTools.h"
43 #include "JackControlAPI.h"
44 #include "JackLockedEngine.h"
45 #include "JackConstants.h"
46 #include "JackDriverLoader.h"
47 #include "JackServerGlobals.h"
48 
49 using namespace Jack;
50 
51 /* JackEngine::CheckPortsConnect() has some assumptions about char values */
52 static struct jack_constraint_enum_char_descriptor self_connect_mode_constraint_descr_array[] =
53 {
54  { ' ', "Don't restrict self connect requests" },
55  { 'E', "Fail self connect requests to external ports only" },
56  { 'e', "Ignore self connect requests to external ports only" },
57  { 'A', "Fail all self connect requests" },
58  { 'a', "Ignore all self connect requests" },
59  { 0 }
60 };
61 
63 {
64  JSList * drivers;
65  JSList * internals;
66  JSList * parameters;
67 
68  class JackServer * engine;
69 
70  /* string, server name */
71  union jackctl_parameter_value name;
72  union jackctl_parameter_value default_name;
73 
74  /* bool, whether to be "realtime" */
75  union jackctl_parameter_value realtime;
76  union jackctl_parameter_value default_realtime;
77 
78  /* int32_t */
79  union jackctl_parameter_value realtime_priority;
80  union jackctl_parameter_value default_realtime_priority;
81 
82  /* bool, whether to exit once all clients have closed their connections */
83  union jackctl_parameter_value temporary;
84  union jackctl_parameter_value default_temporary;
85 
86  /* bool, whether to be verbose */
87  union jackctl_parameter_value verbose;
88  union jackctl_parameter_value default_verbose;
89 
90  /* int32_t, msecs; if zero, use period size. */
91  union jackctl_parameter_value client_timeout;
92  union jackctl_parameter_value default_client_timeout;
93 
94  /* uint32_t, clock source type */
95  union jackctl_parameter_value clock_source;
96  union jackctl_parameter_value default_clock_source;
97 
98  /* uint32_t, max port number */
99  union jackctl_parameter_value port_max;
100  union jackctl_parameter_value default_port_max;
101 
102  /* bool */
103  union jackctl_parameter_value replace_registry;
104  union jackctl_parameter_value default_replace_registry;
105 
106  /* bool, synchronous or asynchronous engine mode */
107  union jackctl_parameter_value sync;
108  union jackctl_parameter_value default_sync;
109 
110  /* char enum, self connect mode mode */
111  union jackctl_parameter_value self_connect_mode;
112  union jackctl_parameter_value default_self_connect_mode;
113 };
114 
116 {
117  jack_driver_desc_t * desc_ptr;
118  JSList * parameters;
119  JSList * infos;
120 };
121 
123 {
124  jack_driver_desc_t * desc_ptr;
125  JSList * parameters;
126  int refnum;
127 };
128 
130 {
131  const char * name;
132  const char * short_description;
133  const char * long_description;
134  jackctl_param_type_t type;
135  bool is_set;
136  union jackctl_parameter_value * value_ptr;
137  union jackctl_parameter_value * default_value_ptr;
138 
139  union jackctl_parameter_value value;
140  union jackctl_parameter_value default_value;
141  struct jackctl_driver * driver_ptr;
142  char id;
143  jack_driver_param_constraint_desc_t * constraint_ptr;
144 };
145 
146 const char * jack_get_self_connect_mode_description(char mode)
147 {
148  struct jack_constraint_enum_char_descriptor * descr_ptr;
149 
150  for (descr_ptr = self_connect_mode_constraint_descr_array;
151  descr_ptr->value;
152  descr_ptr++)
153  if (descr_ptr->value == mode) return descr_ptr->short_desc;
154 
155  return NULL;
156 }
157 
158 static
159 struct jackctl_parameter *
160 jackctl_add_parameter(
161  JSList ** parameters_list_ptr_ptr,
162  const char * name,
163  const char * short_description,
164  const char * long_description,
165  jackctl_param_type_t type,
166  union jackctl_parameter_value * value_ptr,
167  union jackctl_parameter_value * default_value_ptr,
168  union jackctl_parameter_value value,
169  jack_driver_param_constraint_desc_t * constraint_ptr = NULL)
170 {
171  struct jackctl_parameter * parameter_ptr;
172 
173  parameter_ptr = (struct jackctl_parameter *)malloc(sizeof(struct jackctl_parameter));
174  if (parameter_ptr == NULL)
175  {
176  jack_error("Cannot allocate memory for jackctl_parameter structure.");
177  goto fail;
178  }
179 
180  parameter_ptr->name = name;
181  parameter_ptr->short_description = short_description;
182  parameter_ptr->long_description = long_description;
183  parameter_ptr->type = type;
184  parameter_ptr->is_set = false;
185 
186  if (value_ptr == NULL)
187  {
188  value_ptr = &parameter_ptr->value;
189  }
190 
191  if (default_value_ptr == NULL)
192  {
193  default_value_ptr = &parameter_ptr->default_value;
194  }
195 
196  parameter_ptr->value_ptr = value_ptr;
197  parameter_ptr->default_value_ptr = default_value_ptr;
198 
199  *value_ptr = *default_value_ptr = value;
200 
201  parameter_ptr->driver_ptr = NULL;
202  parameter_ptr->id = 0;
203  parameter_ptr->constraint_ptr = constraint_ptr;
204 
205  *parameters_list_ptr_ptr = jack_slist_append(*parameters_list_ptr_ptr, parameter_ptr);
206 
207  return parameter_ptr;
208 
209 fail:
210  return NULL;
211 }
212 
213 static
214 void
215 jackctl_free_driver_parameters(
216  struct jackctl_driver * driver_ptr)
217 {
218  JSList * next_node_ptr;
219 
220  while (driver_ptr->parameters)
221  {
222  next_node_ptr = driver_ptr->parameters->next;
223  free(driver_ptr->parameters->data);
224  free(driver_ptr->parameters);
225  driver_ptr->parameters = next_node_ptr;
226  }
227 }
228 
229 static
230 bool
231 jackctl_add_driver_parameters(
232  struct jackctl_driver * driver_ptr)
233 {
234  unsigned int i;
235 
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;
240 
241  for (i = 0 ; i < driver_ptr->desc_ptr->nparams ; i++)
242  {
243  descriptor_ptr = driver_ptr->desc_ptr->params + i;
244 
245  switch (descriptor_ptr->type)
246  {
247  case JackDriverParamInt:
248  jackctl_type = JackParamInt;
249  jackctl_value.i = descriptor_ptr->value.i;
250  break;
251  case JackDriverParamUInt:
252  jackctl_type = JackParamUInt;
253  jackctl_value.ui = descriptor_ptr->value.ui;
254  break;
255  case JackDriverParamChar:
256  jackctl_type = JackParamChar;
257  jackctl_value.c = descriptor_ptr->value.c;
258  break;
259  case JackDriverParamString:
260  jackctl_type = JackParamString;
261  strcpy(jackctl_value.str, descriptor_ptr->value.str);
262  break;
263  case JackDriverParamBool:
264  jackctl_type = JackParamBool;
265  jackctl_value.b = descriptor_ptr->value.i;
266  break;
267  default:
268  jack_error("Unknown driver parameter type %i", (int)descriptor_ptr->type);
269  assert(0);
270  goto fail;
271  }
272 
273  parameter_ptr = jackctl_add_parameter(
274  &driver_ptr->parameters,
275  descriptor_ptr->name,
276  descriptor_ptr->short_desc,
277  descriptor_ptr->long_desc,
278  jackctl_type,
279  NULL,
280  NULL,
281  jackctl_value,
282  descriptor_ptr->constraint);
283 
284  if (parameter_ptr == NULL)
285  {
286  goto fail;
287  }
288 
289  parameter_ptr->driver_ptr = driver_ptr;
290  parameter_ptr->id = descriptor_ptr->character;
291  }
292 
293  return true;
294 
295 fail:
296  jackctl_free_driver_parameters(driver_ptr);
297 
298  return false;
299 }
300 
301 /* destroy jack_driver_param_desc_t list created by jackctl_create_param_list() */
302 static void
303 jackctl_destroy_param_list(
304  JSList * params)
305 {
306  JSList * next;
307 
308  while (params)
309  {
310  next = params->next;
311  free(params->data);
312  free(params);
313  params = next;
314  }
315 }
316 
317 /* for drivers and internals are configured through jack_driver_param_t JSList */
318 /* this function creates such list from a jackctl_parameter list */
319 static
320 bool
321 jackctl_create_param_list(
322  const JSList * paramlist,
323  JSList ** retparamlist)
324 {
325  jackctl_parameter * param_ptr;
326  jack_driver_param_t * retparam_ptr;
327 
328  *retparamlist = NULL;
329  while (paramlist != NULL)
330  {
331  param_ptr = (jackctl_parameter *)paramlist->data;
332  if (param_ptr->is_set)
333  {
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)
337  {
338  jack_error ("Allocation of jack_driver_param_t structure failed");
339  goto destroy;
340  }
341 
342  retparam_ptr->character = param_ptr->id;
343 
344  switch (param_ptr->type)
345  {
346  case JackParamInt:
347  retparam_ptr->value.i = param_ptr->value_ptr->i;
348  break;
349  case JackParamUInt:
350  retparam_ptr->value.ui = param_ptr->value_ptr->ui;
351  break;
352  case JackParamChar:
353  retparam_ptr->value.c = param_ptr->value_ptr->c;
354  break;
355  case JackParamString:
356  strcpy(retparam_ptr->value.str, param_ptr->value_ptr->str);
357  break;
358  case JackParamBool:
359  retparam_ptr->value.i = param_ptr->value_ptr->b;
360  break;
361  default:
362  jack_error("Unknown parameter type %i", (int)param_ptr->type);
363  assert(0);
364  goto free;
365  }
366 
367  *retparamlist = jack_slist_append(*retparamlist, retparam_ptr);
368  }
369 
370  paramlist = paramlist->next;
371  }
372 
373  return true;
374 
375 free:
376  free(retparam_ptr);
377 destroy:
378  jackctl_destroy_param_list(*retparamlist);
379  return false;
380 }
381 
382 static int
383 jackctl_drivers_load(
384  struct jackctl_server * server_ptr)
385 {
386  struct jackctl_driver * driver_ptr;
387  JSList *node_ptr;
388  JSList *descriptor_node_ptr;
389 
390  descriptor_node_ptr = jack_drivers_load(NULL);
391  if (descriptor_node_ptr == NULL)
392  {
393  jack_error("Could not find any drivers in driver directory!");
394  return false;
395  }
396 
397  while (descriptor_node_ptr != NULL)
398  {
399  driver_ptr = (struct jackctl_driver *)malloc(sizeof(struct jackctl_driver));
400  if (driver_ptr == NULL)
401  {
402  jack_error("Memory allocation of jackctl_driver structure failed.");
403  goto next;
404  }
405 
406  driver_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
407  driver_ptr->parameters = NULL;
408  driver_ptr->infos = NULL;
409 
410  if (!jackctl_add_driver_parameters(driver_ptr))
411  {
412  assert(driver_ptr->parameters == NULL);
413  free(driver_ptr);
414  goto next;
415  }
416 
417  server_ptr->drivers = jack_slist_append(server_ptr->drivers, driver_ptr);
418 
419  next:
420  node_ptr = descriptor_node_ptr;
421  descriptor_node_ptr = descriptor_node_ptr->next;
422  free(node_ptr);
423  }
424 
425  return true;
426 }
427 
428 static
429 void
430 jackctl_server_free_drivers(
431  struct jackctl_server * server_ptr)
432 {
433  JSList * next_node_ptr;
434  struct jackctl_driver * driver_ptr;
435 
436  while (server_ptr->drivers)
437  {
438  next_node_ptr = server_ptr->drivers->next;
439  driver_ptr = (struct jackctl_driver *)server_ptr->drivers->data;
440 
441  jackctl_free_driver_parameters(driver_ptr);
442  free(driver_ptr->desc_ptr->params);
443  free(driver_ptr->desc_ptr);
444  free(driver_ptr);
445 
446  free(server_ptr->drivers);
447  server_ptr->drivers = next_node_ptr;
448  }
449 }
450 
451 static int
452 jackctl_internals_load(
453  struct jackctl_server * server_ptr)
454 {
455  struct jackctl_internal * internal_ptr;
456  JSList *node_ptr;
457  JSList *descriptor_node_ptr;
458 
459  descriptor_node_ptr = jack_internals_load(NULL);
460  if (descriptor_node_ptr == NULL)
461  {
462  jack_error("Could not find any internals in driver directory!");
463  return false;
464  }
465 
466  while (descriptor_node_ptr != NULL)
467  {
468  internal_ptr = (struct jackctl_internal *)malloc(sizeof(struct jackctl_internal));
469  if (internal_ptr == NULL)
470  {
471  jack_error("Memory allocation of jackctl_driver structure failed.");
472  goto next;
473  }
474 
475  internal_ptr->desc_ptr = (jack_driver_desc_t *)descriptor_node_ptr->data;
476  internal_ptr->parameters = NULL;
477  internal_ptr->refnum = -1;
478 
479  if (!jackctl_add_driver_parameters((struct jackctl_driver *)internal_ptr))
480  {
481  assert(internal_ptr->parameters == NULL);
482  free(internal_ptr);
483  goto next;
484  }
485 
486  server_ptr->internals = jack_slist_append(server_ptr->internals, internal_ptr);
487 
488  next:
489  node_ptr = descriptor_node_ptr;
490  descriptor_node_ptr = descriptor_node_ptr->next;
491  free(node_ptr);
492  }
493 
494  return true;
495 }
496 
497 static
498 void
499 jackctl_server_free_internals(
500  struct jackctl_server * server_ptr)
501 {
502  JSList * next_node_ptr;
503  struct jackctl_internal * internal_ptr;
504 
505  while (server_ptr->internals)
506  {
507  next_node_ptr = server_ptr->internals->next;
508  internal_ptr = (struct jackctl_internal *)server_ptr->internals->data;
509 
510  jackctl_free_driver_parameters((struct jackctl_driver *)internal_ptr);
511  free(internal_ptr->desc_ptr->params);
512  free(internal_ptr->desc_ptr);
513  free(internal_ptr);
514 
515  free(server_ptr->internals);
516  server_ptr->internals = next_node_ptr;
517  }
518 }
519 
520 static
521 void
522 jackctl_server_free_parameters(
523  struct jackctl_server * server_ptr)
524 {
525  JSList * next_node_ptr;
526 
527  while (server_ptr->parameters)
528  {
529  next_node_ptr = server_ptr->parameters->next;
530  free(server_ptr->parameters->data);
531  free(server_ptr->parameters);
532  server_ptr->parameters = next_node_ptr;
533  }
534 }
535 
536 #ifdef WIN32
537 
538 struct jackctl_sigmask
539 {
540  HANDLE wait_event;
541 };
542 
543 static jackctl_sigmask sigmask;
544 
545 static void signal_handler(int signum)
546 {
547  printf("Jack main caught signal %d\n", signum);
548  (void) signal(SIGINT, SIG_DFL);
549  SetEvent(sigmask.wait_event);
550 }
551 
554  unsigned int flags)
555 {
556  if ((sigmask.wait_event = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) {
557  jack_error("CreateEvent fails err = %ld", GetLastError());
558  return 0;
559  }
560 
561  (void) signal(SIGINT, signal_handler);
562  (void) signal(SIGABRT, signal_handler);
563  (void) signal(SIGTERM, signal_handler);
564 
565  return &sigmask;
566 }
567 
569 {
570  if (WaitForSingleObject(signals->wait_event, INFINITE) != WAIT_OBJECT_0) {
571  jack_error("WaitForSingleObject fails err = %ld", GetLastError());
572  }
573 }
574 
575 #else
576 
578 {
579  sigset_t signals;
580 };
581 
582 static jackctl_sigmask sigmask;
583 
584 static
585 void
586 signal_handler(int sig)
587 {
588  /* this is used by the child (active) process, but it never
589  gets called unless we are already shutting down after
590  another signal.
591  */
592  char buf[64];
593  snprintf(buf, sizeof(buf), "Received signal %d during shutdown (ignored)\n", sig);
594 }
595 
596 SERVER_EXPORT jackctl_sigmask_t *
598  unsigned int flags)
599 {
600  sigset_t allsignals;
601  struct sigaction action;
602  int i;
603 
604  /* ensure that we are in our own process group so that
605  kill (SIG, -pgrp) does the right thing.
606  */
607 
608  setsid();
609 
610  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
611 
612  /* what's this for?
613 
614  POSIX says that signals are delivered like this:
615 
616  * if a thread has blocked that signal, it is not
617  a candidate to receive the signal.
618  * of all threads not blocking the signal, pick
619  one at random, and deliver the signal.
620 
621  this means that a simple-minded multi-threaded program can
622  expect to get POSIX signals delivered randomly to any one
623  of its threads,
624 
625  here, we block all signals that we think we might receive
626  and want to catch. all "child" threads will inherit this
627  setting. if we create a thread that calls sigwait() on the
628  same set of signals, implicitly unblocking all those
629  signals. any of those signals that are delivered to the
630  process will be delivered to that thread, and that thread
631  alone. this makes cleanup for a signal-driven exit much
632  easier, since we know which thread is doing it and more
633  importantly, we are free to call async-unsafe functions,
634  because the code is executing in normal thread context
635  after a return from sigwait().
636  */
637 
638  sigemptyset(&sigmask.signals);
639  sigaddset(&sigmask.signals, SIGHUP);
640  sigaddset(&sigmask.signals, SIGINT);
641  sigaddset(&sigmask.signals, SIGQUIT);
642  sigaddset(&sigmask.signals, SIGPIPE);
643  sigaddset(&sigmask.signals, SIGTERM);
644 #ifndef __ANDROID__
645  /* android's bionic c doesn't provide pthread_cancel() and related functions.
646  * to solve this issue, use pthread_kill() & SIGUSR1 instead.
647  */
648  sigaddset(&sigmask.signals, SIGUSR1);
649 #endif
650  sigaddset(&sigmask.signals, SIGUSR2);
651 
652  /* all child threads will inherit this mask unless they
653  * explicitly reset it
654  */
655 
656  pthread_sigmask(SIG_BLOCK, &sigmask.signals, 0);
657 
658  /* install a do-nothing handler because otherwise pthreads
659  behaviour is undefined when we enter sigwait.
660  */
661 
662  sigfillset(&allsignals);
663  action.sa_handler = signal_handler;
664  action.sa_mask = allsignals;
665  action.sa_flags = SA_RESTART|SA_RESETHAND;
666 
667  for (i = 1; i < NSIG; i++)
668  {
669  if (sigismember (&sigmask.signals, i))
670  {
671  sigaction(i, &action, 0);
672  }
673  }
674 
675  return &sigmask;
676 }
677 
678 SERVER_EXPORT void
680 {
681  int sig;
682  bool waiting = true;
683 
684  while (waiting) {
685  #if defined(sun) && !defined(__sun__) // SUN compiler only, to check
686  sigwait(&sigmask->signals);
687  #else
688  sigwait(&sigmask->signals, &sig);
689  #endif
690  fprintf(stderr, "Jack main caught signal %d\n", sig);
691 
692  switch (sig) {
693  case SIGUSR1:
694  //jack_dump_configuration(engine, 1);
695  break;
696  case SIGUSR2:
697  // driver exit
698  waiting = false;
699  break;
700  case SIGTTOU:
701  break;
702  default:
703  waiting = false;
704  break;
705  }
706  }
707 
708  if (sig != SIGSEGV) {
709  // unblock signals so we can see them during shutdown.
710  // this will help prod developers not to lose sight of
711  // bugs that cause segfaults etc. during shutdown.
712  sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0);
713  }
714 }
715 #endif
716 
717 static
719 get_realtime_priority_constraint()
720 {
721  jack_driver_param_constraint_desc_t * constraint_ptr;
722  int min, max;
723 
724  if (!jack_get_thread_realtime_priority_range(&min, &max))
725  {
726  return NULL;
727  }
728 
729  //jack_info("realtime priority range is (%d,%d)", min, max);
730 
731  constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_constraint_desc_t));
732  if (constraint_ptr == NULL)
733  {
734  jack_error("Cannot allocate memory for jack_driver_param_constraint_desc_t structure.");
735  return NULL;
736  }
737  constraint_ptr->flags = JACK_CONSTRAINT_FLAG_RANGE;
738 
739  constraint_ptr->constraint.range.min.i = min;
740  constraint_ptr->constraint.range.max.i = max;
741 
742  return constraint_ptr;
743 }
744 
746  bool (* on_device_acquire)(const char * device_name),
747  void (* on_device_release)(const char * device_name))
748 {
749  struct jackctl_server * server_ptr;
750  union jackctl_parameter_value value;
751 
752  server_ptr = (struct jackctl_server *)malloc(sizeof(struct jackctl_server));
753  if (server_ptr == NULL)
754  {
755  jack_error("Cannot allocate memory for jackctl_server structure.");
756  goto fail;
757  }
758 
759  server_ptr->drivers = NULL;
760  server_ptr->internals = NULL;
761  server_ptr->parameters = NULL;
762  server_ptr->engine = NULL;
763 
764  strcpy(value.str, JackTools::DefaultServerName());
765  if (jackctl_add_parameter(
766  &server_ptr->parameters,
767  "name",
768  "Server name to use.",
769  "",
771  &server_ptr->name,
772  &server_ptr->default_name,
773  value) == NULL)
774  {
775  goto fail_free_parameters;
776  }
777 
778  value.b = true;
779  if (jackctl_add_parameter(
780  &server_ptr->parameters,
781  "realtime",
782  "Whether to use realtime mode.",
783  "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.",
785  &server_ptr->realtime,
786  &server_ptr->default_realtime,
787  value) == NULL)
788  {
789  goto fail_free_parameters;
790  }
791 
792  struct utsname utsname;
793  int success;
794  success = uname( &utsname );
795  if( success == 0 && strstr( utsname.version, "PREEMPT RT" ) )
796  value.i = 60;
797  else
798  value.i = 20;
799 
800  if (jackctl_add_parameter(
801  &server_ptr->parameters,
802  "realtime-priority",
803  "Scheduler priority when running in realtime mode.",
804  "",
805  JackParamInt,
806  &server_ptr->realtime_priority,
807  &server_ptr->default_realtime_priority,
808  value,
809  get_realtime_priority_constraint()) == NULL)
810  {
811  goto fail_free_parameters;
812  }
813 
814  value.b = false;
815  if (jackctl_add_parameter(
816  &server_ptr->parameters,
817  "temporary",
818  "Exit once all clients have closed their connections.",
819  "",
821  &server_ptr->temporary,
822  &server_ptr->default_temporary,
823  value) == NULL)
824  {
825  goto fail_free_parameters;
826  }
827 
828  value.b = false;
829  if (jackctl_add_parameter(
830  &server_ptr->parameters,
831  "verbose",
832  "Verbose mode.",
833  "",
835  &server_ptr->verbose,
836  &server_ptr->default_verbose,
837  value) == NULL)
838  {
839  goto fail_free_parameters;
840  }
841 
842  value.i = 0;
843  if (jackctl_add_parameter(
844  &server_ptr->parameters,
845  "client-timeout",
846  "Client timeout limit in milliseconds.",
847  "",
848  JackParamInt,
849  &server_ptr->client_timeout,
850  &server_ptr->default_client_timeout,
851  value) == NULL)
852  {
853  goto fail_free_parameters;
854  }
855 
856  value.ui = 0;
857  if (jackctl_add_parameter(
858  &server_ptr->parameters,
859  "clock-source",
860  "Clocksource type : c(ycle) | h(pet) | s(ystem).",
861  "",
863  &server_ptr->clock_source,
864  &server_ptr->default_clock_source,
865  value) == NULL)
866  {
867  goto fail_free_parameters;
868  }
869 
870  value.ui = PORT_NUM;
871  if (jackctl_add_parameter(
872  &server_ptr->parameters,
873  "port-max",
874  "Maximum number of ports.",
875  "",
877  &server_ptr->port_max,
878  &server_ptr->default_port_max,
879  value) == NULL)
880  {
881  goto fail_free_parameters;
882  }
883 
884  value.b = false;
885  if (jackctl_add_parameter(
886  &server_ptr->parameters,
887  "replace-registry",
888  "Replace shared memory registry.",
889  "",
891  &server_ptr->replace_registry,
892  &server_ptr->default_replace_registry,
893  value) == NULL)
894  {
895  goto fail_free_parameters;
896  }
897 
898  value.b = false;
899  if (jackctl_add_parameter(
900  &server_ptr->parameters,
901  "sync",
902  "Use server synchronous mode.",
903  "",
905  &server_ptr->sync,
906  &server_ptr->default_sync,
907  value) == NULL)
908  {
909  goto fail_free_parameters;
910  }
911 
912  value.c = JACK_DEFAULT_SELF_CONNECT_MODE;
913  if (jackctl_add_parameter(
914  &server_ptr->parameters,
915  "self-connect-mode",
916  "Self connect mode.",
917  "Whether JACK clients are allowed to connect their own ports",
919  &server_ptr->self_connect_mode,
920  &server_ptr->default_self_connect_mode,
921  value,
922  jack_constraint_compose_enum_char(
923  JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE,
924  self_connect_mode_constraint_descr_array)) == NULL)
925  {
926  goto fail_free_parameters;
927  }
928 
929  JackServerGlobals::on_device_acquire = on_device_acquire;
930  JackServerGlobals::on_device_release = on_device_release;
931 
932  if (!jackctl_drivers_load(server_ptr))
933  {
934  goto fail_free_parameters;
935  }
936 
937  /* Allowed to fail */
938  jackctl_internals_load(server_ptr);
939 
940  return server_ptr;
941 
942 fail_free_parameters:
943  jackctl_server_free_parameters(server_ptr);
944 
945  free(server_ptr);
946 
947 fail:
948  return NULL;
949 }
950 
951 SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
952 {
953  if (server_ptr) {
954  jackctl_server_free_drivers(server_ptr);
955  jackctl_server_free_internals(server_ptr);
956  jackctl_server_free_parameters(server_ptr);
957  free(server_ptr);
958  }
959 }
960 
961 SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
962 {
963  return (server_ptr) ? server_ptr->drivers : NULL;
964 }
965 
966 SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
967 {
968  if (server_ptr) {
969  server_ptr->engine->Stop();
970  return true;
971  } else {
972  return false;
973  }
974 }
975 
976 SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
977 {
978  if (server_ptr) {
979  server_ptr->engine->Close();
980  delete server_ptr->engine;
981 
982  /* clean up shared memory and files from this server instance */
983  jack_log("Cleaning up shared memory");
984 
985  jack_cleanup_shm();
986 
987  jack_log("Cleaning up files");
988 
989  JackTools::CleanupFiles(server_ptr->name.str);
990 
991  jack_log("Unregistering server `%s'", server_ptr->name.str);
992 
993  jack_unregister_server(server_ptr->name.str);
994 
995  server_ptr->engine = NULL;
996 
997  return true;
998  } else {
999  return false;
1000  }
1001 }
1002 
1003 SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
1004 {
1005  return (server_ptr) ? server_ptr->parameters : NULL;
1006 }
1007 
1008 SERVER_EXPORT bool
1010  jackctl_server *server_ptr,
1011  jackctl_driver *driver_ptr)
1012 {
1013  JSList * paramlist = NULL;
1014 
1015  try {
1016 
1017  if (!server_ptr || !driver_ptr) {
1018  return false;
1019  }
1020 
1021  int rc = jack_register_server(server_ptr->name.str, server_ptr->replace_registry.b);
1022  switch (rc)
1023  {
1024  case EEXIST:
1025  jack_error("`%s' server already active", server_ptr->name.str);
1026  goto fail;
1027  case ENOSPC:
1028  jack_error("Too many servers already active");
1029  goto fail;
1030  case ENOMEM:
1031  jack_error("No access to shm registry");
1032  goto fail;
1033  }
1034 
1035  jack_log("Server `%s' registered", server_ptr->name.str);
1036 
1037  /* clean up shared memory and files from any previous
1038  * instance of this server name */
1039  jack_cleanup_shm();
1040  JackTools::CleanupFiles(server_ptr->name.str);
1041 
1042  if (!server_ptr->realtime.b && server_ptr->client_timeout.i == 0) {
1043  server_ptr->client_timeout.i = 500; /* 0.5 sec; usable when non realtime. */
1044  }
1045 
1046  /* check port max value before allocating server */
1047  if (server_ptr->port_max.ui > PORT_NUM_MAX) {
1048  jack_error("Jack server started with too much ports %d (when port max can be %d)", server_ptr->port_max.ui, PORT_NUM_MAX);
1049  goto fail;
1050  }
1051 
1052  /* get the engine/driver started */
1053  server_ptr->engine = new JackServer(
1054  server_ptr->sync.b,
1055  server_ptr->temporary.b,
1056  server_ptr->client_timeout.i,
1057  server_ptr->realtime.b,
1058  server_ptr->realtime_priority.i,
1059  server_ptr->port_max.ui,
1060  server_ptr->verbose.b,
1061  (jack_timer_type_t)server_ptr->clock_source.ui,
1062  server_ptr->self_connect_mode.c,
1063  server_ptr->name.str);
1064  if (server_ptr->engine == NULL)
1065  {
1066  jack_error("Failed to create new JackServer object");
1067  goto fail_unregister;
1068  }
1069 
1070  if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) goto fail_delete;
1071  rc = server_ptr->engine->Open(driver_ptr->desc_ptr, paramlist);
1072  jackctl_destroy_param_list(paramlist);
1073  if (rc < 0)
1074  {
1075  jack_error("JackServer::Open failed with %d", rc);
1076  goto fail_delete;
1077  }
1078 
1079  return true;
1080 
1081  } catch (std::exception e) {
1082  jack_error("jackctl_server_open error...");
1083  jackctl_destroy_param_list(paramlist);
1084  }
1085 
1086 fail_delete:
1087  delete server_ptr->engine;
1088  server_ptr->engine = NULL;
1089 
1090 fail_unregister:
1091  jack_log("Cleaning up shared memory");
1092 
1093  jack_cleanup_shm();
1094 
1095  jack_log("Cleaning up files");
1096 
1097  JackTools::CleanupFiles(server_ptr->name.str);
1098 
1099  jack_log("Unregistering server `%s'", server_ptr->name.str);
1100 
1101  jack_unregister_server(server_ptr->name.str);
1102 
1103 fail:
1104  return false;
1105 }
1106 
1107 SERVER_EXPORT bool
1109  jackctl_server *server_ptr)
1110 {
1111  if (!server_ptr) {
1112  return false;
1113  } else {
1114  int rc = server_ptr->engine->Start();
1115  bool result = rc >= 0;
1116  if (! result)
1117  {
1118  jack_error("JackServer::Start() failed with %d", rc);
1119  }
1120  return result;
1121  }
1122 }
1123 
1124 SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
1125 {
1126  return (driver_ptr) ? driver_ptr->desc_ptr->name : NULL;
1127 }
1128 
1129 SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr)
1130 {
1131  return (driver_ptr) ? (jackctl_driver_type_t)driver_ptr->desc_ptr->type : (jackctl_driver_type_t)0;
1132 }
1133 
1134 SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
1135 {
1136  return (driver_ptr) ? driver_ptr->parameters : NULL;
1137 }
1138 
1139 SERVER_EXPORT jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver *driver_ptr)
1140 {
1141  return (driver_ptr) ? driver_ptr->desc_ptr : NULL;
1142 }
1143 
1144 SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
1145 {
1146  return (parameter_ptr) ? parameter_ptr->name : NULL;
1147 }
1148 
1149 SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
1150 {
1151  return (parameter_ptr) ? parameter_ptr->short_description : NULL;
1152 }
1153 
1154 SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
1155 {
1156  return (parameter_ptr) ? parameter_ptr->long_description : NULL;
1157 }
1158 
1160 {
1161  return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) != 0) : false;
1162 }
1163 
1165 {
1166  return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0): false;
1167 }
1168 
1170 {
1171  if (!parameter_ptr) {
1172  return 0;
1173  }
1174 
1175  if (!jackctl_parameter_has_enum_constraint(parameter_ptr))
1176  {
1177  return 0;
1178  }
1179 
1180  return parameter_ptr->constraint_ptr->constraint.enumeration.count;
1181  }
1182 
1184 {
1185  jack_driver_param_value_t * value_ptr;
1186  union jackctl_parameter_value jackctl_value;
1187 
1188  if (!parameter_ptr) {
1189  memset(&jackctl_value, 0, sizeof(jackctl_value));
1190  return jackctl_value;
1191  }
1192 
1193  value_ptr = &parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].value;
1194 
1195  switch (parameter_ptr->type)
1196  {
1197  case JackParamInt:
1198  jackctl_value.i = value_ptr->i;
1199  break;
1200  case JackParamUInt:
1201  jackctl_value.ui = value_ptr->ui;
1202  break;
1203  case JackParamChar:
1204  jackctl_value.c = value_ptr->c;
1205  break;
1206  case JackParamString:
1207  strcpy(jackctl_value.str, value_ptr->str);
1208  break;
1209  default:
1210  jack_error("Bad driver parameter type %i (enum constraint)", (int)parameter_ptr->type);
1211  assert(0);
1212  }
1213 
1214  return jackctl_value;
1215 }
1216 
1217 SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
1218 {
1219  return (parameter_ptr) ? parameter_ptr->constraint_ptr->constraint.enumeration.possible_values_array[index].short_desc : NULL;
1220 }
1221 
1222 SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value * min_ptr, union jackctl_parameter_value * max_ptr)
1223 {
1224  if (!parameter_ptr || !min_ptr || !max_ptr) {
1225  return;
1226  }
1227 
1228  switch (parameter_ptr->type)
1229  {
1230  case JackParamInt:
1231  min_ptr->i = parameter_ptr->constraint_ptr->constraint.range.min.i;
1232  max_ptr->i = parameter_ptr->constraint_ptr->constraint.range.max.i;
1233  return;
1234  case JackParamUInt:
1235  min_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.min.ui;
1236  max_ptr->ui = parameter_ptr->constraint_ptr->constraint.range.max.ui;
1237  return;
1238  default:
1239  jack_error("Bad driver parameter type %i (range constraint)", (int)parameter_ptr->type);
1240  assert(0);
1241  }
1242 }
1243 
1245 {
1246  return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_STRICT) != 0) : false;
1247 }
1248 
1250 {
1251  return (parameter_ptr) ? (parameter_ptr->constraint_ptr != NULL && (parameter_ptr->constraint_ptr->flags & JACK_CONSTRAINT_FLAG_FAKE_VALUE) != 0) : false;
1252 }
1253 
1254 SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
1255 {
1256  return (parameter_ptr) ? parameter_ptr->type : (jackctl_param_type_t)0;
1257 }
1258 
1259 SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t * parameter_ptr)
1260 {
1261  return (parameter_ptr) ? parameter_ptr->id : 0;
1262 }
1263 
1264 SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
1265 {
1266  return (parameter_ptr) ? parameter_ptr->is_set : false;
1267 }
1268 
1270 {
1271  if (parameter_ptr) {
1272  return *parameter_ptr->value_ptr;
1273  } else {
1274  union jackctl_parameter_value jackctl_value;
1275  memset(&jackctl_value, 0, sizeof(jackctl_value));
1276  return jackctl_value;
1277  }
1278 }
1279 
1280 SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
1281 {
1282  if (!parameter_ptr) {
1283  return NULL;
1284  }
1285 
1286  if (!parameter_ptr->is_set)
1287  {
1288  return true;
1289  }
1290 
1291  parameter_ptr->is_set = false;
1292 
1293  *parameter_ptr->value_ptr = *parameter_ptr->default_value_ptr;
1294 
1295  return true;
1296 }
1297 
1298 SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value * value_ptr)
1299 {
1300  if (!parameter_ptr || !value_ptr) {
1301  return NULL;
1302  }
1303 
1304  parameter_ptr->is_set = true;
1305  *parameter_ptr->value_ptr = *value_ptr;
1306 
1307  return true;
1308 }
1309 
1311 {
1312  if (parameter_ptr) {
1313  return *parameter_ptr->default_value_ptr;
1314  } else {
1315  union jackctl_parameter_value jackctl_value;
1316  memset(&jackctl_value, 0, sizeof(jackctl_value));
1317  return jackctl_value;
1318  }
1319 }
1320 
1321 // Internals clients
1322 
1323 SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
1324 {
1325  return (server_ptr) ? server_ptr->internals : NULL;
1326 }
1327 
1328 SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
1329 {
1330  return (internal_ptr) ? internal_ptr->desc_ptr->name : NULL;
1331 }
1332 
1333 SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
1334 {
1335  return (internal_ptr) ? internal_ptr->parameters : NULL;
1336 }
1337 
1338 SERVER_EXPORT bool jackctl_server_load_internal(
1339  jackctl_server * server_ptr,
1340  jackctl_internal * internal)
1341 {
1342  if (!server_ptr || !internal) {
1343  return false;
1344  }
1345 
1346  int status;
1347  if (server_ptr->engine != NULL) {
1348  JSList * paramlist;
1349  if (!jackctl_create_param_list(internal->parameters, &paramlist)) return false;
1350  server_ptr->engine->InternalClientLoad2(internal->desc_ptr->name, internal->desc_ptr->name, paramlist, JackNullOption, &internal->refnum, -1, &status);
1351  jackctl_destroy_param_list(paramlist);
1352  return (internal->refnum > 0);
1353  } else {
1354  return false;
1355  }
1356 }
1357 
1359  jackctl_server * server_ptr,
1360  jackctl_internal * internal)
1361 {
1362  if (!server_ptr || !internal) {
1363  return false;
1364  }
1365 
1366  int status;
1367  if (server_ptr->engine != NULL && internal->refnum > 0) {
1368  // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
1369  return ((server_ptr->engine->GetEngine()->InternalClientUnload(internal->refnum, &status)) == 0);
1370  } else {
1371  return false;
1372  }
1373 }
1374 
1375 SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1376 {
1377  if (server_ptr && server_ptr->engine) {
1378  if (server_ptr->engine->IsRunning()) {
1379  jack_error("Cannot add a slave in a running server");
1380  return false;
1381  } else {
1382  JSList * paramlist;
1383  if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) return false;
1384  JackDriverInfo* info = server_ptr->engine->AddSlave(driver_ptr->desc_ptr, paramlist);
1385  jackctl_destroy_param_list(paramlist);
1386  if (info) {
1387  driver_ptr->infos = jack_slist_append(driver_ptr->infos, info);
1388  return true;
1389  } else {
1390  return false;
1391  }
1392  }
1393  } else {
1394  return false;
1395  }
1396 }
1397 
1398 SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1399 {
1400  if (server_ptr && server_ptr->engine) {
1401  if (server_ptr->engine->IsRunning()) {
1402  jack_error("Cannot remove a slave from a running server");
1403  return false;
1404  } else {
1405  if (driver_ptr->infos) {
1406  JackDriverInfo* info = (JackDriverInfo*)driver_ptr->infos->data;
1407  assert(info);
1408  driver_ptr->infos = jack_slist_remove(driver_ptr->infos, info);
1409  server_ptr->engine->RemoveSlave(info);
1410  delete info;
1411  return true;
1412  } else {
1413  return false;
1414  }
1415  }
1416  } else {
1417  return false;
1418  }
1419 }
1420 
1421 SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server * server_ptr, jackctl_driver * driver_ptr)
1422 {
1423  if (server_ptr && server_ptr->engine) {
1424  JSList * paramlist;
1425  if (!jackctl_create_param_list(driver_ptr->parameters, &paramlist)) return false;
1426  bool ret = (server_ptr->engine->SwitchMaster(driver_ptr->desc_ptr, paramlist) == 0);
1427  jackctl_destroy_param_list(paramlist);
1428  return ret;
1429  } else {
1430  return false;
1431  }
1432 }
1433 
1434 
SERVER_EXPORT const char * jackctl_parameter_get_long_description(jackctl_parameter *parameter_ptr)
jackctl_driver_type_t
Definition: control.h:50
value type is a signed integer
Definition: control.h:42
SERVER_EXPORT bool jackctl_parameter_is_set(jackctl_parameter *parameter_ptr)
SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_value(jackctl_parameter *parameter_ptr)
SERVER_EXPORT jackctl_sigmask_t * jackctl_setup_signals(unsigned int flags)
char str[JACK_PARAM_STRING_MAX+1]
member used for JackParamString
SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_default_value(jackctl_parameter *parameter_ptr)
value type is an unsigned integer
Definition: control.h:43
SERVER_EXPORT bool jackctl_server_open(jackctl_server *server_ptr, jackctl_driver *driver_ptr)
SERVER_EXPORT void jackctl_parameter_get_range_constraint(jackctl_parameter *parameter_ptr, union jackctl_parameter_value *min_ptr, union jackctl_parameter_value *max_ptr)
value type is a char
Definition: control.h:44
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
SERVER_EXPORT jackctl_server_t * jackctl_server_create(bool(*on_device_acquire)(const char *device_name), void(*on_device_release)(const char *device_name))
SERVER_EXPORT bool jackctl_parameter_reset(jackctl_parameter *parameter_ptr)
uint32_t ui
member used for JackParamUInt
jack_driver_type_t type
jack_driver_param_value_t value
SERVER_EXPORT bool jackctl_server_switch_master(jackctl_server *server_ptr, jackctl_driver *driver_ptr)
value type is a boolean
Definition: control.h:46
SERVER_EXPORT const char * jackctl_internal_get_name(jackctl_internal *internal_ptr)
int32_t i
member used for JackParamInt
SERVER_EXPORT const char * jackctl_parameter_get_name(jackctl_parameter *parameter_ptr)
SERVER_EXPORT bool jackctl_server_stop(jackctl_server *server_ptr)
bool b
member used for JackParamBool
Type for parameter value.
SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
value type is a string with max size of JACK_PARAM_STRING_MAX+1 chars
Definition: control.h:45
SERVER_EXPORT bool jackctl_parameter_has_range_constraint(jackctl_parameter *parameter_ptr)
SERVER_EXPORT bool jackctl_server_close(jackctl_server *server_ptr)
SERVER_EXPORT bool jackctl_server_remove_slave(jackctl_server *server_ptr, jackctl_driver *driver_ptr)
SERVER_EXPORT const char * jackctl_parameter_get_enum_constraint_description(jackctl_parameter *parameter_ptr, uint32_t index)
SERVER_EXPORT const JSList * jackctl_server_get_internals_list(jackctl_server *server_ptr)
jack_driver_param_constraint_desc_t * constraint
SERVER_EXPORT const char * jackctl_parameter_get_short_description(jackctl_parameter *parameter_ptr)
SERVER_EXPORT bool jackctl_parameter_constraint_is_fake_value(jackctl_parameter_t *parameter_ptr)
struct jack_driver_param_constraint_desc_t::@0::@1 range
SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
SERVER_EXPORT const JSList * jackctl_server_get_drivers_list(jackctl_server *server_ptr)
char name[JACK_DRIVER_NAME_MAX+1]
char name[JACK_DRIVER_NAME_MAX+1]
SERVER_EXPORT bool jackctl_server_start(jackctl_server *server_ptr)
The Jack server.
Definition: JackServer.h:46
SERVER_EXPORT bool jackctl_parameter_constraint_is_strict(jackctl_parameter_t *parameter_ptr)
SERVER_EXPORT uint32_t jackctl_parameter_get_enum_constraints_count(jackctl_parameter *parameter_ptr)
SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value *value_ptr)
SERVER_EXPORT bool jackctl_server_add_slave(jackctl_server *server_ptr, jackctl_driver *driver_ptr)
jackctl_param_type_t
Definition: control.h:40
SERVER_EXPORT const char * jackctl_driver_get_name(jackctl_driver *driver_ptr)
SERVER_EXPORT union jackctl_parameter_value jackctl_parameter_get_enum_constraint_value(jackctl_parameter *parameter_ptr, uint32_t index)
SERVER_EXPORT bool jackctl_server_unload_internal(jackctl_server *server_ptr, jackctl_internal *internal)
jack_driver_param_type_t type
SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t *parameter_ptr)
SERVER_EXPORT const JSList * jackctl_internal_get_parameters(jackctl_internal *internal_ptr)
struct jack_driver_param_constraint_desc_t::@0::@2 enumeration
SERVER_EXPORT void jackctl_server_destroy(jackctl_server *server_ptr)
SERVER_EXPORT jackctl_driver_type_t jackctl_driver_get_type(jackctl_driver *driver_ptr)
char c
member used for JackParamChar
SERVER_EXPORT const JSList * jackctl_server_get_parameters(jackctl_server *server_ptr)
SERVER_EXPORT bool jackctl_parameter_has_enum_constraint(jackctl_parameter *parameter_ptr)
SERVER_EXPORT void jackctl_wait_signals(jackctl_sigmask_t *sigmask)
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
SERVER_EXPORT bool jackctl_server_load_internal(jackctl_server *server_ptr, jackctl_internal *internal)
jack_driver_param_desc_t * params