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