Jack2  1.9.11-RC1
JackDriverLoader.cpp
1 /*
2 Copyright (C) 2001-2005 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include "JackSystemDeps.h"
22 #include "JackDriverLoader.h"
23 #include "JackDriverInfo.h"
24 #include "JackConstants.h"
25 #include "JackError.h"
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <string.h>
30 
31 #ifndef WIN32
32 #include <dirent.h>
33 #endif
34 
35 #ifdef WIN32
36 
37 static char* locate_dll_driver_dir()
38 {
39 #ifdef _WIN64
40  HMODULE libjack_handle = LoadLibrary("libjackserver64.dll");
41 #else
42  HMODULE libjack_handle = LoadLibrary("libjackserver.dll");
43 #endif
44 
45  // For WIN32 ADDON_DIR is defined in JackConstants.h as relative path
46  char driver_dir_storage[512];
47  if (3 < GetModuleFileName(libjack_handle, driver_dir_storage, 512)) {
48  char *p = strrchr(driver_dir_storage, '\\');
49  if (p && (p != driver_dir_storage)) {
50  *p = 0;
51  }
52  jack_info("Drivers/internals found in : %s", driver_dir_storage);
53  strcat(driver_dir_storage, "/");
54  strcat(driver_dir_storage, ADDON_DIR);
55  FreeLibrary(libjack_handle);
56  return strdup(driver_dir_storage);
57  } else {
58  jack_error("Cannot get JACK dll directory : %d", GetLastError());
59  FreeLibrary(libjack_handle);
60  return NULL;
61  }
62 }
63 
64 static char* locate_driver_dir(HANDLE& file, WIN32_FIND_DATA& filedata)
65 {
66  // Search drivers/internals iin the same folder of "libjackserver.dll"
67  char* driver_dir = locate_dll_driver_dir();
68  char dll_filename[512];
69  snprintf(dll_filename, sizeof(dll_filename), "%s/*.dll", driver_dir);
70  file = (HANDLE)FindFirstFile(dll_filename, &filedata);
71 
72  if (file == INVALID_HANDLE_VALUE) {
73  jack_error("Drivers not found ");
74  free(driver_dir);
75  return NULL;
76  } else {
77  return driver_dir;
78  }
79 }
80 
81 #endif
82 
83 jack_driver_desc_t* jackctl_driver_get_desc(jackctl_driver_t * driver);
84 
85 void jack_print_driver_options(jack_driver_desc_t* desc, FILE* file)
86 {
87  unsigned long i;
88  char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
89 
90  for (i = 0; i < desc->nparams; i++) {
91  switch (desc->params[i].type) {
92  case JackDriverParamInt:
93  sprintf (arg_default, "%" "i", desc->params[i].value.i);
94  break;
95  case JackDriverParamUInt:
96  sprintf (arg_default, "%" "u", desc->params[i].value.ui);
97  break;
98  case JackDriverParamChar:
99  sprintf (arg_default, "%c", desc->params[i].value.c);
100  break;
101  case JackDriverParamString:
102  if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0) {
103  sprintf (arg_default, "%s", desc->params[i].value.str);
104  } else {
105  sprintf (arg_default, "none");
106  }
107  break;
108  case JackDriverParamBool:
109  sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
110  break;
111  }
112 
113  fprintf(file, "\t-%c, --%s \t%s (default: %s)\n",
114  desc->params[i].character,
115  desc->params[i].name,
116  desc->params[i].long_desc,
117  arg_default);
118  }
119 }
120 
121 static void jack_print_driver_param_usage (jack_driver_desc_t* desc, unsigned long param, FILE *file)
122 {
123  fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
124  desc->params[param].name, desc->name);
125  fprintf (file, "%s\n", desc->params[param].long_desc);
126 }
127 
128 void jack_free_driver_params(JSList * driver_params)
129 {
130  JSList*node_ptr = driver_params;
131  JSList*next_node_ptr;
132 
133  while (node_ptr) {
134  next_node_ptr = node_ptr->next;
135  free(node_ptr->data);
136  free(node_ptr);
137  node_ptr = next_node_ptr;
138  }
139 }
140 
141 int jack_parse_driver_params(jack_driver_desc_t* desc, int argc, char* argv[], JSList** param_ptr)
142 {
143  struct option * long_options;
144  char* options, * options_ptr;
145  unsigned long i;
146  int opt;
147  unsigned int param_index;
148  JSList* params = NULL;
149  jack_driver_param_t * driver_param;
150 
151  if (argc <= 1) {
152  *param_ptr = NULL;
153  return 0;
154  }
155 
156  /* check for help */
157  if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
158  if (argc > 2) {
159  for (i = 0; i < desc->nparams; i++) {
160  if (strcmp (desc->params[i].name, argv[2]) == 0) {
161  jack_print_driver_param_usage (desc, i, stdout);
162  return 1;
163  }
164  }
165 
166  fprintf (stderr, "Jackd: unknown option '%s' "
167  "for driver '%s'\n", argv[2],
168  desc->name);
169  }
170 
171  jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
172  jack_print_driver_options (desc, stdout);
173  return 1;
174  }
175 
176  /* set up the stuff for getopt */
177  options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
178  long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
179 
180  options_ptr = options;
181  for (i = 0; i < desc->nparams; i++) {
182  sprintf (options_ptr, "%c::", desc->params[i].character);
183  options_ptr += 3;
184  long_options[i].name = desc->params[i].name;
185  long_options[i].flag = NULL;
186  long_options[i].val = desc->params[i].character;
187  long_options[i].has_arg = optional_argument;
188  }
189 
190  /* create the params */
191  optind = 0;
192  opterr = 0;
193  while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
194 
195  if (opt == ':' || opt == '?') {
196  if (opt == ':') {
197  fprintf (stderr, "Missing option to argument '%c'\n", optopt);
198  } else {
199  fprintf (stderr, "Unknownage with option '%c'\n", optopt);
200  }
201 
202  fprintf (stderr, "Options for driver '%s':\n", desc->name);
203  jack_print_driver_options (desc, stderr);
204  return 1;
205  }
206 
207  for (param_index = 0; param_index < desc->nparams; param_index++) {
208  if (opt == desc->params[param_index].character) {
209  break;
210  }
211  }
212 
213  driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
214  driver_param->character = desc->params[param_index].character;
215 
216  if (!optarg && optind < argc &&
217  strlen(argv[optind]) &&
218  argv[optind][0] != '-') {
219  optarg = argv[optind];
220  }
221 
222  if (optarg) {
223  switch (desc->params[param_index].type) {
224  case JackDriverParamInt:
225  driver_param->value.i = atoi(optarg);
226  break;
227  case JackDriverParamUInt:
228  driver_param->value.ui = strtoul(optarg, NULL, 10);
229  break;
230  case JackDriverParamChar:
231  driver_param->value.c = optarg[0];
232  break;
233  case JackDriverParamString:
234  strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
235  break;
236  case JackDriverParamBool:
237  if (strcasecmp("false", optarg) == 0 ||
238  strcasecmp("off", optarg) == 0 ||
239  strcasecmp("no", optarg) == 0 ||
240  strcasecmp("0", optarg) == 0 ||
241  strcasecmp("(null)", optarg) == 0 ) {
242  driver_param->value.i = false;
243  } else {
244  driver_param->value.i = true;
245  }
246  break;
247  }
248  } else {
249  if (desc->params[param_index].type == JackDriverParamBool) {
250  driver_param->value.i = true;
251  } else {
252  driver_param->value = desc->params[param_index].value;
253  }
254  }
255 
256  params = jack_slist_append (params, driver_param);
257  }
258 
259  free (options);
260  free (long_options);
261 
262  if (param_ptr) {
263  *param_ptr = params;
264  }
265  return 0;
266 }
267 
268 SERVER_EXPORT int jackctl_driver_params_parse(jackctl_driver *driver_ptr, int argc, char* argv[])
269 {
270  struct option* long_options;
271  char* options, * options_ptr;
272  unsigned long i;
273  int opt;
274  JSList* node_ptr;
275  jackctl_parameter_t * param = NULL;
276  union jackctl_parameter_value value;
277 
278  if (argc <= 1) {
279  return 0;
280  }
281 
282  const JSList* driver_params = jackctl_driver_get_parameters(driver_ptr);
283  if (driver_params == NULL) {
284  return 1;
285  }
286 
287  jack_driver_desc_t* desc = jackctl_driver_get_desc(driver_ptr);
288 
289  /* check for help */
290  if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
291  if (argc > 2) {
292  for (i = 0; i < desc->nparams; i++) {
293  if (strcmp (desc->params[i].name, argv[2]) == 0) {
294  jack_print_driver_param_usage (desc, i, stdout);
295  return 1;
296  }
297  }
298 
299  fprintf (stderr, "Jackd: unknown option '%s' "
300  "for driver '%s'\n", argv[2],
301  desc->name);
302  }
303 
304  jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
305  jack_print_driver_options (desc, stdout);
306  return 1;
307  }
308 
309  /* set up the stuff for getopt */
310  options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
311  long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
312 
313  options_ptr = options;
314  for (i = 0; i < desc->nparams; i++) {
315  sprintf(options_ptr, "%c::", desc->params[i].character);
316  options_ptr += 3;
317  long_options[i].name = desc->params[i].name;
318  long_options[i].flag = NULL;
319  long_options[i].val = desc->params[i].character;
320  long_options[i].has_arg = optional_argument;
321  }
322 
323  /* create the params */
324  optind = 0;
325  opterr = 0;
326  while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
327 
328  if (opt == ':' || opt == '?') {
329  if (opt == ':') {
330  fprintf (stderr, "Missing option to argument '%c'\n", optopt);
331  } else {
332  fprintf (stderr, "Unknownage with option '%c'\n", optopt);
333  }
334 
335  fprintf (stderr, "Options for driver '%s':\n", desc->name);
336  jack_print_driver_options(desc, stderr);
337  return 1;
338  }
339 
340  node_ptr = (JSList *)driver_params;
341  while (node_ptr) {
342  param = (jackctl_parameter_t*)node_ptr->data;
343  if (opt == jackctl_parameter_get_id(param)) {
344  break;
345  }
346  node_ptr = node_ptr->next;
347  }
348 
349  if (!optarg && optind < argc &&
350  strlen(argv[optind]) &&
351  argv[optind][0] != '-') {
352  optarg = argv[optind];
353  }
354 
355  if (optarg) {
356  switch (jackctl_parameter_get_type(param)) {
357  case JackDriverParamInt:
358  value.i = atoi(optarg);
359  jackctl_parameter_set_value(param, &value);
360  break;
361  case JackDriverParamUInt:
362  value.ui = strtoul(optarg, NULL, 10);
363  jackctl_parameter_set_value(param, &value);
364  break;
365  case JackDriverParamChar:
366  value.c = optarg[0];
367  jackctl_parameter_set_value(param, &value);
368  break;
369  case JackDriverParamString:
370  strncpy(value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
371  jackctl_parameter_set_value(param, &value);
372  break;
373  case JackDriverParamBool:
374  if (strcasecmp("false", optarg) == 0 ||
375  strcasecmp("off", optarg) == 0 ||
376  strcasecmp("no", optarg) == 0 ||
377  strcasecmp("0", optarg) == 0 ||
378  strcasecmp("(null)", optarg) == 0 ) {
379  value.i = false;
380  } else {
381  value.i = true;
382  }
383  jackctl_parameter_set_value(param, &value);
384  break;
385  }
386  } else {
388  value.i = true;
389  } else {
391  }
392  jackctl_parameter_set_value(param, &value);
393  }
394  }
395 
396  free(options);
397  free(long_options);
398  return 0;
399 }
400 
401 jack_driver_desc_t* jack_find_driver_descriptor (JSList * drivers, const char* name)
402 {
403  jack_driver_desc_t* desc = 0;
404  JSList* node;
405 
406  for (node = drivers; node; node = jack_slist_next (node)) {
407  desc = (jack_driver_desc_t*) node->data;
408 
409  if (strcmp (desc->name, name) != 0) {
410  desc = NULL;
411  } else {
412  break;
413  }
414  }
415 
416  return desc;
417 }
418 
419 static void* check_symbol(const char* sofile, const char* symbol, const char* driver_dir, void** res_dllhandle = NULL)
420 {
421  void* dlhandle;
422  void* res = NULL;
423  char filename[1024];
424  sprintf(filename, "%s/%s", driver_dir, sofile);
425 
426  if ((dlhandle = LoadDriverModule(filename)) == NULL) {
427 #ifdef WIN32
428  jack_error ("Could not open component .dll '%s': %ld", filename, GetLastError());
429 #else
430  jack_error ("Could not open component .so '%s': %s", filename, dlerror());
431 #endif
432  } else {
433  res = (void*)GetDriverProc(dlhandle, symbol);
434  if (res_dllhandle) {
435  *res_dllhandle = dlhandle;
436  } else {
437  UnloadDriverModule(dlhandle);
438  }
439  }
440 
441  return res;
442 }
443 
444 static jack_driver_desc_t* jack_get_descriptor (JSList* drivers, const char* sofile, const char* symbol, const char* driver_dir)
445 {
446  jack_driver_desc_t* descriptor = NULL;
447  jack_driver_desc_t* other_descriptor;
448  JackDriverDescFunction so_get_descriptor = NULL;
449  char filename[1024];
450  JSList* node;
451  void* dlhandle = NULL;
452 
453  sprintf(filename, "%s/%s", driver_dir, sofile);
454  so_get_descriptor = (JackDriverDescFunction)check_symbol(sofile, symbol, driver_dir, &dlhandle);
455 
456  if (so_get_descriptor == NULL) {
457  jack_error("jack_get_descriptor : dll %s is not a driver", sofile);
458  goto error;
459  }
460 
461  if ((descriptor = so_get_descriptor ()) == NULL) {
462  jack_error("Driver from '%s' returned NULL descriptor", filename);
463  goto error;
464  }
465 
466  /* check it doesn't exist already */
467  for (node = drivers; node; node = jack_slist_next (node)) {
468  other_descriptor = (jack_driver_desc_t*) node->data;
469  if (strcmp(descriptor->name, other_descriptor->name) == 0) {
470  jack_error("The drivers in '%s' and '%s' both have the name '%s'; using the first",
471  other_descriptor->file, filename, other_descriptor->name);
472  /* FIXME: delete the descriptor */
473  goto error;
474  }
475  }
476 
477  strncpy(descriptor->file, filename, JACK_PATH_MAX);
478 
479 error:
480  if (dlhandle) {
481  UnloadDriverModule(dlhandle);
482  }
483  return descriptor;
484 }
485 
486 #ifdef WIN32
487 
488 JSList * jack_drivers_load(JSList * drivers)
489 {
490  //char dll_filename[512];
491  WIN32_FIND_DATA filedata;
492  HANDLE file;
493  const char* ptr = NULL;
494  JSList* driver_list = NULL;
495  jack_driver_desc_t* desc = NULL;
496 
497  char* driver_dir = locate_driver_dir(file, filedata);
498  if (!driver_dir) {
499  jack_error("Driver folder not found");
500  goto error;
501  }
502 
503  do {
504  /* check the filename is of the right format */
505  if (strncmp ("jack_", filedata.cFileName, 5) != 0) {
506  continue;
507  }
508 
509  ptr = strrchr (filedata.cFileName, '.');
510  if (!ptr) {
511  continue;
512  }
513 
514  ptr++;
515  if (strncmp ("dll", ptr, 3) != 0) {
516  continue;
517  }
518 
519  /* check if dll is an internal client */
520  if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) != NULL) {
521  continue;
522  }
523 
524  desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor", driver_dir);
525  if (desc) {
526  driver_list = jack_slist_append (driver_list, desc);
527  } else {
528  jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
529  }
530 
531  } while (FindNextFile(file, &filedata));
532 
533  if (!driver_list) {
534  jack_error ("Could not find any drivers in %s!", driver_dir);
535  }
536 
537 error:
538  if (driver_dir) {
539  free(driver_dir);
540  }
541  FindClose(file);
542  return driver_list;
543 }
544 
545 #else
546 
547 JSList* jack_drivers_load (JSList * drivers)
548 {
549  struct dirent * dir_entry;
550  DIR * dir_stream;
551  const char* ptr;
552  int err;
553  JSList* driver_list = NULL;
554  jack_driver_desc_t* desc = NULL;
555 
556  const char* driver_dir;
557  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
558  driver_dir = ADDON_DIR;
559  }
560 
561  /* search through the driver_dir and add get descriptors
562  from the .so files in it */
563  dir_stream = opendir (driver_dir);
564  if (!dir_stream) {
565  jack_error ("Could not open driver directory %s: %s",
566  driver_dir, strerror (errno));
567  return NULL;
568  }
569 
570  while ((dir_entry = readdir(dir_stream))) {
571 
572  /* check the filename is of the right format */
573  if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
574  continue;
575  }
576 
577  ptr = strrchr (dir_entry->d_name, '.');
578  if (!ptr) {
579  continue;
580  }
581  ptr++;
582  if (strncmp ("so", ptr, 2) != 0) {
583  continue;
584  }
585 
586  /* check if dll is an internal client */
587  if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) != NULL) {
588  continue;
589  }
590 
591  desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor", driver_dir);
592  if (desc) {
593  driver_list = jack_slist_append (driver_list, desc);
594  } else {
595  jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
596  }
597  }
598 
599  err = closedir (dir_stream);
600  if (err) {
601  jack_error ("Error closing driver directory %s: %s",
602  driver_dir, strerror (errno));
603  }
604 
605  if (!driver_list) {
606  jack_error ("Could not find any drivers in %s!", driver_dir);
607  return NULL;
608  }
609 
610  return driver_list;
611 }
612 
613 #endif
614 
615 #ifdef WIN32
616 
617 JSList* jack_internals_load(JSList * internals)
618 {
620  WIN32_FIND_DATA filedata;
621  HANDLE file;
622  const char* ptr = NULL;
623  JSList* driver_list = NULL;
624  jack_driver_desc_t* desc;
625 
626  char* driver_dir = locate_driver_dir(file, filedata);
627  if (!driver_dir) {
628  jack_error("Driver folder not found");
629  goto error;
630  }
631 
632  do {
633 
634  ptr = strrchr (filedata.cFileName, '.');
635  if (!ptr) {
636  continue;
637  }
638 
639  ptr++;
640  if (strncmp ("dll", ptr, 3) != 0) {
641  continue;
642  }
643 
644  /* check if dll is an internal client */
645  if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) == NULL) {
646  continue;
647  }
648 
649  desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor", driver_dir);
650  if (desc) {
651  driver_list = jack_slist_append (driver_list, desc);
652  } else {
653  jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
654  }
655 
656  } while (FindNextFile(file, &filedata));
657 
658  if (!driver_list) {
659  jack_error ("Could not find any internals in %s!", driver_dir);
660  }
661 
662  error:
663  if (driver_dir) {
664  free(driver_dir);
665  }
666  FindClose(file);
667  return driver_list;
668 }
669 
670 #else
671 
672 JSList* jack_internals_load(JSList * internals)
673 {
674  struct dirent * dir_entry;
675  DIR * dir_stream;
676  const char* ptr;
677  int err;
678  JSList* driver_list = NULL;
679  jack_driver_desc_t* desc;
680 
681  const char* driver_dir;
682  if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
683  driver_dir = ADDON_DIR;
684  }
685 
686  /* search through the driver_dir and add get descriptors
687  from the .so files in it */
688  dir_stream = opendir (driver_dir);
689  if (!dir_stream) {
690  jack_error ("Could not open driver directory %s: %s\n",
691  driver_dir, strerror (errno));
692  return NULL;
693  }
694 
695  while ((dir_entry = readdir(dir_stream))) {
696 
697  ptr = strrchr (dir_entry->d_name, '.');
698  if (!ptr) {
699  continue;
700  }
701 
702  ptr++;
703  if (strncmp ("so", ptr, 2) != 0) {
704  continue;
705  }
706 
707  /* check if dll is an internal client */
708  if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) == NULL) {
709  continue;
710  }
711 
712  desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor", driver_dir);
713  if (desc) {
714  driver_list = jack_slist_append (driver_list, desc);
715  } else {
716  jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
717  }
718  }
719 
720  err = closedir (dir_stream);
721  if (err) {
722  jack_error ("Error closing internal directory %s: %s\n",
723  driver_dir, strerror (errno));
724  }
725 
726  if (!driver_list) {
727  jack_error ("Could not find any internals in %s!", driver_dir);
728  return NULL;
729  }
730 
731  return driver_list;
732 }
733 
734 #endif
735 
736 Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc,
737  Jack::JackLockedEngine* engine,
738  Jack::JackSynchro* synchro,
739  const JSList* params)
740 {
741 #ifdef WIN32
742  int errstr;
743 #else
744  const char* errstr;
745 #endif
746 
747  fHandle = LoadDriverModule (driver_desc->file);
748 
749  if (fHandle == NULL) {
750 #ifdef WIN32
751  if ((errstr = GetLastError ()) != 0) {
752  jack_error ("Can't load \"%s\": %ld", driver_desc->file, errstr);
753 #else
754  if ((errstr = dlerror ()) != 0) {
755  jack_error ("Can't load \"%s\": %s", driver_desc->file, errstr);
756 #endif
757 
758  } else {
759  jack_error ("Error loading driver shared object %s", driver_desc->file);
760  }
761  return NULL;
762  }
763 
764  fInitialize = (driverInitialize)GetDriverProc(fHandle, "driver_initialize");
765 
766 #ifdef WIN32
767  if ((fInitialize == NULL) && (errstr = GetLastError ()) != 0) {
768 #else
769  if ((fInitialize == NULL) && (errstr = dlerror ()) != 0) {
770 #endif
771  jack_error("No initialize function in shared object %s\n", driver_desc->file);
772  return NULL;
773  }
774 
775  fBackend = fInitialize(engine, synchro, params);
776  return fBackend;
777 }
778 
779 JackDriverInfo::~JackDriverInfo()
780 {
781  delete fBackend;
782  if (fHandle) {
783  UnloadDriverModule(fHandle);
784  }
785 }
786 
787 SERVER_EXPORT jack_driver_desc_t* jack_driver_descriptor_construct(
788  const char * name,
789  jack_driver_type_t type,
790  const char * description,
791  jack_driver_desc_filler_t * filler_ptr)
792 {
793  size_t name_len;
794  size_t description_len;
795  jack_driver_desc_t* desc_ptr;
796 
797  name_len = strlen(name);
798  description_len = strlen(description);
799 
800  if (name_len > sizeof(desc_ptr->name) - 1 ||
801  description_len > sizeof(desc_ptr->desc) - 1) {
802  assert(false);
803  return 0;
804  }
805 
806  desc_ptr = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t));
807  if (desc_ptr == NULL) {
808  jack_error("Error calloc() failed to allocate memory for driver descriptor struct");
809  return 0;
810  }
811 
812  memcpy(desc_ptr->name, name, name_len + 1);
813  memcpy(desc_ptr->desc, description, description_len + 1);
814 
815  desc_ptr->nparams = 0;
816  desc_ptr->type = type;
817 
818  if (filler_ptr != NULL) {
819  filler_ptr->size = 0;
820  }
821 
822  return desc_ptr;
823 }
824 
825 SERVER_EXPORT int jack_driver_descriptor_add_parameter(
826  jack_driver_desc_t* desc_ptr,
827  jack_driver_desc_filler_t * filler_ptr,
828  const char* name,
829  char character,
830  jack_driver_param_type_t type,
831  const jack_driver_param_value_t * value_ptr,
833  const char* short_desc,
834  const char* long_desc)
835 {
836  size_t name_len;
837  size_t short_desc_len;
838  size_t long_desc_len;
839  jack_driver_param_desc_t * param_ptr;
840  size_t newsize;
841 
842  name_len = strlen(name);
843  short_desc_len = strlen(short_desc);
844 
845  if (long_desc != NULL) {
846  long_desc_len = strlen(long_desc);
847  } else {
848  long_desc = short_desc;
849  long_desc_len = short_desc_len;
850  }
851 
852  if (name_len > sizeof(param_ptr->name) - 1 ||
853  short_desc_len > sizeof(param_ptr->short_desc) - 1 ||
854  long_desc_len > sizeof(param_ptr->long_desc) - 1) {
855  assert(false);
856  return 0;
857  }
858 
859  if (desc_ptr->nparams == filler_ptr->size) {
860  newsize = filler_ptr->size + 20; // most drivers have less than 20 parameters
861  param_ptr = (jack_driver_param_desc_t*)realloc (desc_ptr->params, newsize * sizeof (jack_driver_param_desc_t));
862  if (param_ptr == NULL) {
863  jack_error("Error realloc() failed for parameter array of %zu elements", newsize);
864  return false;
865  }
866  filler_ptr->size = newsize;
867  desc_ptr->params = param_ptr;
868  }
869 
870  assert(desc_ptr->nparams < filler_ptr->size);
871  param_ptr = desc_ptr->params + desc_ptr->nparams;
872 
873  memcpy(param_ptr->name, name, name_len + 1);
874  param_ptr->character = character;
875  param_ptr->type = type;
876  param_ptr->value = *value_ptr;
877  param_ptr->constraint = constraint;
878  memcpy(param_ptr->short_desc, short_desc, short_desc_len + 1);
879  memcpy(param_ptr->long_desc, long_desc, long_desc_len + 1);
880 
881  desc_ptr->nparams++;
882  return true;
883 }
884 
885 SERVER_EXPORT
886 int
887 jack_constraint_add_enum(
888  jack_driver_param_constraint_desc_t ** constraint_ptr_ptr,
889  uint32_t * array_size_ptr,
890  jack_driver_param_value_t * value_ptr,
891  const char * short_desc)
892 {
893  jack_driver_param_constraint_desc_t * constraint_ptr;
894  uint32_t array_size;
895  jack_driver_param_value_enum_t * possible_value_ptr;
896  size_t len;
897 
898  len = strlen(short_desc) + 1;
899  if (len > sizeof(possible_value_ptr->short_desc))
900  {
901  assert(false);
902  return false;
903  }
904 
905  constraint_ptr = *constraint_ptr_ptr;
906  if (constraint_ptr == NULL)
907  {
908  constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_constraint_desc_t));
909  if (constraint_ptr == NULL)
910  {
911  jack_error("calloc() failed to allocate memory for param constraint struct");
912  return false;
913  }
914 
915  array_size = 0;
916  }
917  else
918  {
919  array_size = *array_size_ptr;
920  }
921 
922  if (constraint_ptr->constraint.enumeration.count == array_size)
923  {
924  array_size += 10;
925  possible_value_ptr =
927  constraint_ptr->constraint.enumeration.possible_values_array,
928  sizeof(jack_driver_param_value_enum_t) * array_size);
929  if (possible_value_ptr == NULL)
930  {
931  jack_error("realloc() failed to (re)allocate memory for possible values array");
932  return false;
933  }
934  constraint_ptr->constraint.enumeration.possible_values_array = possible_value_ptr;
935  }
936  else
937  {
938  possible_value_ptr = constraint_ptr->constraint.enumeration.possible_values_array;
939  }
940 
941  possible_value_ptr += constraint_ptr->constraint.enumeration.count;
942  constraint_ptr->constraint.enumeration.count++;
943 
944  possible_value_ptr->value = *value_ptr;
945  memcpy(possible_value_ptr->short_desc, short_desc, len);
946 
947  *constraint_ptr_ptr = constraint_ptr;
948  *array_size_ptr = array_size;
949 
950  return true;
951 }
952 
953 SERVER_EXPORT
954 void
955 jack_constraint_free(
956  jack_driver_param_constraint_desc_t * constraint_ptr)
957 {
958  if (constraint_ptr != NULL)
959  {
960  if ((constraint_ptr->flags & JACK_CONSTRAINT_FLAG_RANGE) == 0)
961  {
962  free(constraint_ptr->constraint.enumeration.possible_values_array);
963  }
964 
965  free(constraint_ptr);
966  }
967 }
968 
969 #define JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(type, copy) \
970 JACK_CONSTRAINT_COMPOSE_ENUM(type) \
971 { \
972  jack_driver_param_constraint_desc_t * constraint_ptr; \
973  uint32_t array_size; \
974  jack_driver_param_value_t value; \
975  struct jack_constraint_enum_ ## type ## _descriptor * descr_ptr; \
976  \
977  constraint_ptr = NULL; \
978  for (descr_ptr = descr_array_ptr; \
979  descr_ptr->value; \
980  descr_ptr++) \
981  { \
982  copy; \
983  if (!jack_constraint_add_enum( \
984  &constraint_ptr, \
985  &array_size, \
986  &value, \
987  descr_ptr->short_desc)) \
988  { \
989  jack_constraint_free(constraint_ptr); \
990  return NULL; \
991  } \
992  } \
993  \
994  constraint_ptr->flags = flags; \
995  \
996  return constraint_ptr; \
997 }
998 
999 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(uint32, value.c = descr_ptr->value);
1000 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(sint32, value.c = descr_ptr->value);
1001 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(char, value.c = descr_ptr->value);
1002 JACK_CONSTRAINT_COMPOSE_ENUM_IMPL(str, strcpy(value.str, descr_ptr->value));
SERVER_EXPORT int jackctl_driver_params_parse(jackctl_driver *driver_ptr, int argc, char *argv[])
Locked Engine, access to methods is serialized using a mutex.
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)
Inter process synchronization using POSIX semaphore.
char file[JACK_PATH_MAX+1]
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
uint32_t ui
member used for JackParamUInt
jack_driver_type_t type
jack_driver_param_value_t value
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
value type is a boolean
Definition: control.h:46
int32_t i
member used for JackParamInt
Definition: getopt.h:84
Type for parameter value.
SERVER_EXPORT const JSList * jackctl_driver_get_parameters(jackctl_driver *driver_ptr)
jack_driver_param_constraint_desc_t * constraint
SERVER_EXPORT jackctl_param_type_t jackctl_parameter_get_type(jackctl_parameter *parameter_ptr)
char name[JACK_DRIVER_NAME_MAX+1]
char name[JACK_DRIVER_NAME_MAX+1]
SERVER_EXPORT bool jackctl_parameter_set_value(jackctl_parameter *parameter_ptr, const union jackctl_parameter_value *value_ptr)
The base interface for drivers clients.
Definition: JackDriver.h:114
char desc[JACK_DRIVER_PARAM_DESC+1]
jack_driver_param_type_t type
SERVER_EXPORT char jackctl_parameter_get_id(jackctl_parameter_t *parameter_ptr)
struct jack_driver_param_constraint_desc_t::@0::@2 enumeration
char c
member used for JackParamChar
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_driver_param_desc_t * params