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