2 Copyright (C) 2001-2005 Paul Davis
3 Copyright (C) 2004-2008 Grame
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.
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.
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.
21 #include "JackSystemDeps.h"
22 #include "JackDriverLoader.h"
23 #include "JackConstants.h"
24 #include "JackError.h"
33 jack_driver_desc_t
* jackctl_driver_get_desc(jackctl_driver_t
* driver
);
35 SERVER_EXPORT
void jack_print_driver_options (jack_driver_desc_t
* desc
, FILE* file
)
38 char arg_default
[JACK_DRIVER_PARAM_STRING_MAX
+ 1];
40 for (i
= 0; i
< desc
->nparams
; i
++) {
41 switch (desc
->params
[i
].type
) {
42 case JackDriverParamInt
:
43 sprintf (arg_default
, "%" "i", desc
->params
[i
].value
.i
);
45 case JackDriverParamUInt
:
46 sprintf (arg_default
, "%" "u", desc
->params
[i
].value
.ui
);
48 case JackDriverParamChar
:
49 sprintf (arg_default
, "%c", desc
->params
[i
].value
.c
);
51 case JackDriverParamString
:
52 if (desc
->params
[i
].value
.str
&& strcmp (desc
->params
[i
].value
.str
, "") != 0)
53 sprintf (arg_default
, "%s", desc
->params
[i
].value
.str
);
55 sprintf (arg_default
, "none");
57 case JackDriverParamBool
:
58 sprintf (arg_default
, "%s", desc
->params
[i
].value
.i
? "true" : "false");
62 fprintf (file
, "\t-%c, --%s \t%s (default: %s)\n",
63 desc
->params
[i
].character
,
65 desc
->params
[i
].long_desc
,
71 jack_print_driver_param_usage (jack_driver_desc_t
* desc
, unsigned long param
, FILE *file
)
73 fprintf (file
, "Usage information for the '%s' parameter for driver '%s':\n",
74 desc
->params
[param
].name
, desc
->name
);
75 fprintf (file
, "%s\n", desc
->params
[param
].long_desc
);
78 SERVER_EXPORT
void jack_free_driver_params(JSList
* driver_params
)
80 JSList
*node_ptr
= driver_params
;
81 JSList
*next_node_ptr
;
84 next_node_ptr
= node_ptr
->next
;
87 node_ptr
= next_node_ptr
;
92 jack_parse_driver_params (jack_driver_desc_t
* desc
, int argc
, char* argv
[], JSList
** param_ptr
)
94 struct option
* long_options
;
95 char * options
, * options_ptr
;
98 unsigned int param_index
;
99 JSList
* params
= NULL
;
100 jack_driver_param_t
* driver_param
;
108 if (strcmp (argv
[1], "-h") == 0 || strcmp (argv
[1], "--help") == 0) {
110 for (i
= 0; i
< desc
->nparams
; i
++) {
111 if (strcmp (desc
->params
[i
].name
, argv
[2]) == 0) {
112 jack_print_driver_param_usage (desc
, i
, stdout
);
117 fprintf (stderr
, "jackd: unknown option '%s' "
118 "for driver '%s'\n", argv
[2],
122 printf ("Parameters for driver '%s' (all parameters are optional):\n", desc
->name
);
123 jack_print_driver_options (desc
, stdout
);
127 /* set up the stuff for getopt */
128 options
= (char*)calloc (desc
->nparams
* 3 + 1, sizeof (char));
129 long_options
= (option
*)calloc (desc
->nparams
+ 1, sizeof (struct option
));
131 options_ptr
= options
;
132 for (i
= 0; i
< desc
->nparams
; i
++) {
133 sprintf (options_ptr
, "%c::", desc
->params
[i
].character
);
135 long_options
[i
].name
= desc
->params
[i
].name
;
136 long_options
[i
].flag
= NULL
;
137 long_options
[i
].val
= desc
->params
[i
].character
;
138 long_options
[i
].has_arg
= optional_argument
;
141 /* create the params */
144 while ((opt
= getopt_long(argc
, argv
, options
, long_options
, NULL
)) != -1) {
146 if (opt
== ':' || opt
== '?') {
148 fprintf (stderr
, "Missing option to argument '%c'\n", optopt
);
150 fprintf (stderr
, "Unknownage with option '%c'\n", optopt
);
153 fprintf (stderr
, "Options for driver '%s':\n", desc
->name
);
154 jack_print_driver_options (desc
, stderr
);
158 for (param_index
= 0; param_index
< desc
->nparams
; param_index
++) {
159 if (opt
== desc
->params
[param_index
].character
) {
164 driver_param
= (jack_driver_param_t
*)calloc (1, sizeof (jack_driver_param_t
));
165 driver_param
->character
= desc
->params
[param_index
].character
;
167 if (!optarg
&& optind
< argc
&&
168 strlen(argv
[optind
]) &&
169 argv
[optind
][0] != '-') {
170 optarg
= argv
[optind
];
174 switch (desc
->params
[param_index
].type
) {
175 case JackDriverParamInt
:
176 driver_param
->value
.i
= atoi (optarg
);
178 case JackDriverParamUInt
:
179 driver_param
->value
.ui
= strtoul (optarg
, NULL
, 10);
181 case JackDriverParamChar
:
182 driver_param
->value
.c
= optarg
[0];
184 case JackDriverParamString
:
185 strncpy (driver_param
->value
.str
, optarg
, JACK_DRIVER_PARAM_STRING_MAX
);
187 case JackDriverParamBool
:
190 if (strcasecmp ("false", optarg) == 0 ||
191 strcasecmp ("off", optarg) == 0 ||
192 strcasecmp ("no", optarg) == 0 ||
193 strcasecmp ("0", optarg) == 0 ||
194 strcasecmp ("(null)", optarg) == 0 ) {
197 if (strcmp ("false", optarg
) == 0 ||
198 strcmp ("off", optarg
) == 0 ||
199 strcmp ("no", optarg
) == 0 ||
200 strcmp ("0", optarg
) == 0 ||
201 strcmp ("(null)", optarg
) == 0 ) {
202 driver_param
->value
.i
= false;
206 driver_param
->value
.i
= true;
212 if (desc
->params
[param_index
].type
== JackDriverParamBool
) {
213 driver_param
->value
.i
= true;
215 driver_param
->value
= desc
->params
[param_index
].value
;
219 params
= jack_slist_append (params
, driver_param
);
232 jackctl_parse_driver_params (jackctl_driver
*driver_ptr
, int argc
, char* argv
[])
234 struct option
* long_options
;
235 char * options
, * options_ptr
;
239 jackctl_parameter_t
* param
= NULL
;
240 union jackctl_parameter_value value
;
245 const JSList
* driver_params
= jackctl_driver_get_parameters(driver_ptr
);
246 if (driver_params
== NULL
)
249 jack_driver_desc_t
* desc
= jackctl_driver_get_desc(driver_ptr
);
252 if (strcmp (argv
[1], "-h") == 0 || strcmp (argv
[1], "--help") == 0) {
254 for (i
= 0; i
< desc
->nparams
; i
++) {
255 if (strcmp (desc
->params
[i
].name
, argv
[2]) == 0) {
256 jack_print_driver_param_usage (desc
, i
, stdout
);
261 fprintf (stderr
, "jackd: unknown option '%s' "
262 "for driver '%s'\n", argv
[2],
266 printf ("Parameters for driver '%s' (all parameters are optional):\n", desc
->name
);
267 jack_print_driver_options (desc
, stdout
);
271 /* set up the stuff for getopt */
272 options
= (char*)calloc (desc
->nparams
* 3 + 1, sizeof (char));
273 long_options
= (option
*)calloc (desc
->nparams
+ 1, sizeof (struct option
));
275 options_ptr
= options
;
276 for (i
= 0; i
< desc
->nparams
; i
++) {
277 sprintf (options_ptr
, "%c::", desc
->params
[i
].character
);
279 long_options
[i
].name
= desc
->params
[i
].name
;
280 long_options
[i
].flag
= NULL
;
281 long_options
[i
].val
= desc
->params
[i
].character
;
282 long_options
[i
].has_arg
= optional_argument
;
285 /* create the params */
288 while ((opt
= getopt_long(argc
, argv
, options
, long_options
, NULL
)) != -1) {
290 if (opt
== ':' || opt
== '?') {
292 fprintf (stderr
, "Missing option to argument '%c'\n", optopt
);
294 fprintf (stderr
, "Unknownage with option '%c'\n", optopt
);
297 fprintf (stderr
, "Options for driver '%s':\n", desc
->name
);
298 jack_print_driver_options(desc
, stderr
);
302 node_ptr
= (JSList
*)driver_params
;
304 param
= (jackctl_parameter_t
*)node_ptr
->data
;
305 if (opt
== jackctl_parameter_get_id(param
)) {
308 node_ptr
= node_ptr
->next
;
311 if (!optarg
&& optind
< argc
&&
312 strlen(argv
[optind
]) &&
313 argv
[optind
][0] != '-') {
314 optarg
= argv
[optind
];
318 switch (jackctl_parameter_get_type(param
)) {
319 case JackDriverParamInt
:
320 value
.i
= atoi (optarg
);
321 jackctl_parameter_set_value(param
, &value
);
323 case JackDriverParamUInt
:
324 value
.ui
= strtoul (optarg
, NULL
, 10);
325 jackctl_parameter_set_value(param
, &value
);
327 case JackDriverParamChar
:
329 jackctl_parameter_set_value(param
, &value
);
331 case JackDriverParamString
:
332 strncpy (value
.str
, optarg
, JACK_DRIVER_PARAM_STRING_MAX
);
333 jackctl_parameter_set_value(param
, &value
);
335 case JackDriverParamBool
:
337 if (strcasecmp ("false", optarg) == 0 ||
338 strcasecmp ("off", optarg) == 0 ||
339 strcasecmp ("no", optarg) == 0 ||
340 strcasecmp ("0", optarg) == 0 ||
341 strcasecmp ("(null)", optarg) == 0 ) {
344 if (strcmp ("false", optarg
) == 0 ||
345 strcmp ("off", optarg
) == 0 ||
346 strcmp ("no", optarg
) == 0 ||
347 strcmp ("0", optarg
) == 0 ||
348 strcmp ("(null)", optarg
) == 0 ) {
353 jackctl_parameter_set_value(param
, &value
);
357 if (jackctl_parameter_get_type(param
) == JackParamBool
) {
360 value
= jackctl_parameter_get_default_value(param
);
362 jackctl_parameter_set_value(param
, &value
);
372 jack_find_driver_descriptor (JSList
* drivers
, const char * name
)
374 jack_driver_desc_t
* desc
= 0;
377 for (node
= drivers
; node
; node
= jack_slist_next (node
)) {
378 desc
= (jack_driver_desc_t
*) node
->data
;
380 if (strcmp (desc
->name
, name
) != 0) {
390 static jack_driver_desc_t
*
391 jack_get_descriptor (JSList
* drivers
, const char * sofile
, const char * symbol
)
393 jack_driver_desc_t
* descriptor
, * other_descriptor
;
394 JackDriverDescFunction so_get_descriptor
= NULL
;
405 const char* driver_dir
;
407 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
408 // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
409 // for posix systems, it is absolute path of default driver dir
411 char temp_driver_dir1
[512];
412 char temp_driver_dir2
[512];
413 GetCurrentDirectory(512, temp_driver_dir1
);
414 sprintf(temp_driver_dir2
, "%s/%s", temp_driver_dir1
, ADDON_DIR
);
415 driver_dir
= temp_driver_dir2
;
417 driver_dir
= ADDON_DIR
;
421 filename
= (char *)malloc(strlen (driver_dir
) + 1 + strlen(sofile
) + 1);
422 sprintf (filename
, "%s/%s", driver_dir
, sofile
);
424 if ((dlhandle
= LoadDriverModule(filename
)) == NULL
) {
426 jack_error ("could not open driver .dll '%s': %ld", filename
, GetLastError());
428 jack_error ("could not open driver .so '%s': %s", filename
, dlerror());
435 so_get_descriptor
= (JackDriverDescFunction
)GetDriverProc(dlhandle
, symbol
);
438 if ((so_get_descriptor
== NULL
) && (dlerr
= GetLastError()) != 0) {
439 jack_log("jack_get_descriptor : dll is not a driver, err = %ld", dlerr
);
441 if ((so_get_descriptor
== NULL
) && (dlerr
= dlerror ()) != NULL
) {
442 jack_log("jack_get_descriptor err = %s", dlerr
);
445 UnloadDriverModule(dlhandle
);
450 if ((descriptor
= so_get_descriptor ()) == NULL
) {
451 jack_error("driver from '%s' returned NULL descriptor", filename
);
452 UnloadDriverModule(dlhandle
);
458 if ((err
= UnloadDriverModule(dlhandle
)) == 0) {
459 jack_error ("error closing driver .so '%s': %ld", filename
, GetLastError ());
462 if ((err
= UnloadDriverModule(dlhandle
)) != 0) {
463 jack_error ("error closing driver .so '%s': %s", filename
, dlerror ());
467 /* check it doesn't exist already */
468 for (node
= drivers
; node
; node
= jack_slist_next (node
)) {
469 other_descriptor
= (jack_driver_desc_t
*) node
->data
;
471 if (strcmp(descriptor
->name
, other_descriptor
->name
) == 0) {
472 jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first",
473 other_descriptor
->file
, filename
, other_descriptor
->name
);
474 /* FIXME: delete the descriptor */
480 strncpy(descriptor
->file
, filename
, JACK_PATH_MAX
);
485 static bool check_symbol(const char* sofile
, const char* symbol
)
489 const char* driver_dir
;
491 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
492 // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
493 // for posix systems, it is absolute path of default driver dir
495 char temp_driver_dir1
[512];
496 char temp_driver_dir2
[512];
497 GetCurrentDirectory(512, temp_driver_dir1
);
498 sprintf(temp_driver_dir2
, "%s/%s", temp_driver_dir1
, ADDON_DIR
);
499 driver_dir
= temp_driver_dir2
;
501 driver_dir
= ADDON_DIR
;
505 char* filename
= (char *)malloc(strlen (driver_dir
) + 1 + strlen(sofile
) + 1);
506 sprintf (filename
, "%s/%s", driver_dir
, sofile
);
508 if ((dlhandle
= LoadDriverModule(filename
)) == NULL
) {
510 jack_error ("could not open component .dll '%s': %ld", filename
, GetLastError());
512 jack_error ("could not open component .so '%s': %s", filename
, dlerror());
515 res
= (GetDriverProc(dlhandle
, symbol
)) ? true : false;
516 UnloadDriverModule(dlhandle
);
526 jack_drivers_load (JSList
* drivers
) {
528 char driver_dir_storage
[512];
529 char dll_filename
[512];
530 WIN32_FIND_DATA filedata
;
532 const char * ptr
= NULL
;
533 JSList
* driver_list
= NULL
;
534 jack_driver_desc_t
* desc
;
536 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
537 // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
538 GetCurrentDirectory(512, driver_dir_storage
);
539 strcat(driver_dir_storage
, "/");
540 strcat(driver_dir_storage
, ADDON_DIR
);
541 driver_dir
= driver_dir_storage
;
544 sprintf(dll_filename
, "%s/*.dll", driver_dir
);
546 file
= (HANDLE
)FindFirstFile(dll_filename
, &filedata
);
548 if (file
== INVALID_HANDLE_VALUE
) {
549 jack_error("error invalid handle");
554 ptr
= strrchr (filedata
.cFileName
, '.');
559 if (strncmp ("dll", ptr
, 3) != 0) {
563 desc
= jack_get_descriptor (drivers
, filedata
.cFileName
, "driver_get_descriptor");
565 driver_list
= jack_slist_append (driver_list
, desc
);
568 } while (FindNextFile(file
, &filedata
));
571 jack_error ("could not find any drivers in %s!", driver_dir
);
581 jack_drivers_load (JSList
* drivers
) {
582 struct dirent
* dir_entry
;
586 JSList
* driver_list
= NULL
;
587 jack_driver_desc_t
* desc
;
589 const char* driver_dir
;
590 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
591 driver_dir
= ADDON_DIR
;
594 /* search through the driver_dir and add get descriptors
595 from the .so files in it */
596 dir_stream
= opendir (driver_dir
);
598 jack_error ("could not open driver directory %s: %s",
599 driver_dir
, strerror (errno
));
603 while ((dir_entry
= readdir(dir_stream
))) {
605 /* check the filename is of the right format */
606 if (strncmp ("jack_", dir_entry
->d_name
, 5) != 0) {
610 ptr
= strrchr (dir_entry
->d_name
, '.');
615 if (strncmp ("so", ptr
, 2) != 0) {
619 desc
= jack_get_descriptor (drivers
, dir_entry
->d_name
, "driver_get_descriptor");
621 driver_list
= jack_slist_append (driver_list
, desc
);
625 err
= closedir (dir_stream
);
627 jack_error ("error closing driver directory %s: %s",
628 driver_dir
, strerror (errno
));
632 jack_error ("could not find any drivers in %s!", driver_dir
);
644 jack_internals_load (JSList
* internals
) {
646 char driver_dir_storage
[512];
647 char dll_filename
[512];
648 WIN32_FIND_DATA filedata
;
650 const char * ptr
= NULL
;
651 JSList
* driver_list
= NULL
;
652 jack_driver_desc_t
* desc
;
654 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
655 // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
656 GetCurrentDirectory(512, driver_dir_storage
);
657 strcat(driver_dir_storage
, "/");
658 strcat(driver_dir_storage
, ADDON_DIR
);
659 driver_dir
= driver_dir_storage
;
662 sprintf(dll_filename
, "%s/*.dll", driver_dir
);
664 file
= (HANDLE
)FindFirstFile(dll_filename
, &filedata
);
666 if (file
== INVALID_HANDLE_VALUE
) {
673 ptr
= strrchr (filedata
.cFileName
, '.');
678 if (strncmp ("dll", ptr
, 3) != 0) {
682 /* check if dll is an internal client */
683 if (!check_symbol(filedata
.cFileName
, "jack_internal_initialize")) {
687 desc
= jack_get_descriptor (internals
, filedata
.cFileName
, "jack_get_descriptor");
689 driver_list
= jack_slist_append (driver_list
, desc
);
692 } while (FindNextFile(file
, &filedata
));
695 jack_error ("could not find any internals in %s!", driver_dir
);
705 jack_internals_load (JSList
* internals
) {
706 struct dirent
* dir_entry
;
710 JSList
* driver_list
= NULL
;
711 jack_driver_desc_t
* desc
;
713 const char* driver_dir
;
714 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
715 driver_dir
= ADDON_DIR
;
718 /* search through the driver_dir and add get descriptors
719 from the .so files in it */
720 dir_stream
= opendir (driver_dir
);
722 jack_error ("could not open driver directory %s: %s\n",
723 driver_dir
, strerror (errno
));
727 while ((dir_entry
= readdir(dir_stream
))) {
729 ptr
= strrchr (dir_entry
->d_name
, '.');
734 if (strncmp ("so", ptr
, 2) != 0) {
738 /* check if dll is an internal client */
739 if (!check_symbol(dir_entry
->d_name
, "jack_internal_initialize")) {
743 desc
= jack_get_descriptor (internals
, dir_entry
->d_name
, "jack_get_descriptor");
745 driver_list
= jack_slist_append (driver_list
, desc
);
749 err
= closedir (dir_stream
);
751 jack_error ("error closing internal directory %s: %s\n",
752 driver_dir
, strerror (errno
));
756 jack_error ("could not find any internals in %s!", driver_dir
);
765 Jack::JackDriverClientInterface
* JackDriverInfo::Open(jack_driver_desc_t
* driver_desc
,
766 Jack::JackLockedEngine
* engine
,
767 Jack::JackSynchro
* synchro
,
768 const JSList
* params
)
776 fHandle
= LoadDriverModule (driver_desc
->file
);
778 if (fHandle
== NULL
) {
780 if ((errstr
= GetLastError ()) != 0) {
781 jack_error ("can't load \"%s\": %ld", driver_desc
->file
, errstr
);
783 if ((errstr
= dlerror ()) != 0) {
784 jack_error ("can't load \"%s\": %s", driver_desc
->file
, errstr
);
788 jack_error ("bizarre error loading driver shared object %s", driver_desc
->file
);
793 fInitialize
= (driverInitialize
)GetDriverProc(fHandle
, "driver_initialize");
796 if ((fInitialize
== NULL
) && (errstr
= GetLastError ()) != 0) {
798 if ((fInitialize
== NULL
) && (errstr
= dlerror ()) != 0) {
800 jack_error("no initialize function in shared object %s\n", driver_desc
->file
);
804 fBackend
= fInitialize(engine
, synchro
, params
);