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