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 "JackDriverInfo.h"
24 #include "JackConstants.h"
25 #include "JackError.h"
37 static char* locate_dll_driver_dir()
40 HMODULE libjack_handle
= LoadLibrary("libjackserver64.dll");
42 HMODULE libjack_handle
= LoadLibrary("libjackserver.dll");
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
)) {
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
);
58 jack_error("Cannot get JACK dll directory : %d", GetLastError());
59 FreeLibrary(libjack_handle
);
64 static char* locate_driver_dir(HANDLE
& file
, WIN32_FIND_DATA
& filedata
)
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
);
72 if (file
== INVALID_HANDLE_VALUE
) {
73 jack_error("Drivers not found ");
83 jack_driver_desc_t
* jackctl_driver_get_desc(jackctl_driver_t
* driver
);
85 void jack_print_driver_options(jack_driver_desc_t
* desc
, FILE* file
)
88 char arg_default
[JACK_DRIVER_PARAM_STRING_MAX
+ 1];
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
);
95 case JackDriverParamUInt
:
96 sprintf (arg_default
, "%" "u", desc
->params
[i
].value
.ui
);
98 case JackDriverParamChar
:
99 sprintf (arg_default
, "%c", desc
->params
[i
].value
.c
);
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
);
105 sprintf (arg_default
, "none");
108 case JackDriverParamBool
:
109 sprintf (arg_default
, "%s", desc
->params
[i
].value
.i
? "true" : "false");
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
,
121 static void jack_print_driver_param_usage (jack_driver_desc_t
* desc
, unsigned long param
, FILE *file
)
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
);
128 void jack_free_driver_params(JSList
* driver_params
)
130 JSList
*node_ptr
= driver_params
;
131 JSList
*next_node_ptr
;
134 next_node_ptr
= node_ptr
->next
;
135 free(node_ptr
->data
);
137 node_ptr
= next_node_ptr
;
141 int jack_parse_driver_params(jack_driver_desc_t
* desc
, int argc
, char* argv
[], JSList
** param_ptr
)
143 struct option
* long_options
;
144 char* options
, * options_ptr
;
147 unsigned int param_index
;
148 JSList
* params
= NULL
;
149 jack_driver_param_t
* driver_param
;
157 if (strcmp (argv
[1], "-h") == 0 || strcmp (argv
[1], "--help") == 0) {
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
);
166 fprintf (stderr
, "Jackd: unknown option '%s' "
167 "for driver '%s'\n", argv
[2],
171 jack_log("Parameters for driver '%s' (all parameters are optional):", desc
->name
);
172 jack_print_driver_options (desc
, stdout
);
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
));
180 options_ptr
= options
;
181 for (i
= 0; i
< desc
->nparams
; i
++) {
182 sprintf (options_ptr
, "%c::", desc
->params
[i
].character
);
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
;
190 /* create the params */
193 while ((opt
= getopt_long(argc
, argv
, options
, long_options
, NULL
)) != -1) {
195 if (opt
== ':' || opt
== '?') {
197 fprintf (stderr
, "Missing option to argument '%c'\n", optopt
);
199 fprintf (stderr
, "Unknownage with option '%c'\n", optopt
);
202 fprintf (stderr
, "Options for driver '%s':\n", desc
->name
);
203 jack_print_driver_options (desc
, stderr
);
207 for (param_index
= 0; param_index
< desc
->nparams
; param_index
++) {
208 if (opt
== desc
->params
[param_index
].character
) {
213 driver_param
= (jack_driver_param_t
*)calloc (1, sizeof (jack_driver_param_t
));
214 driver_param
->character
= desc
->params
[param_index
].character
;
216 if (!optarg
&& optind
< argc
&&
217 strlen(argv
[optind
]) &&
218 argv
[optind
][0] != '-') {
219 optarg
= argv
[optind
];
223 switch (desc
->params
[param_index
].type
) {
224 case JackDriverParamInt
:
225 driver_param
->value
.i
= atoi(optarg
);
227 case JackDriverParamUInt
:
228 driver_param
->value
.ui
= strtoul(optarg
, NULL
, 10);
230 case JackDriverParamChar
:
231 driver_param
->value
.c
= optarg
[0];
233 case JackDriverParamString
:
234 strncpy (driver_param
->value
.str
, optarg
, JACK_DRIVER_PARAM_STRING_MAX
);
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;
244 driver_param
->value
.i
= true;
249 if (desc
->params
[param_index
].type
== JackDriverParamBool
) {
250 driver_param
->value
.i
= true;
252 driver_param
->value
= desc
->params
[param_index
].value
;
256 params
= jack_slist_append (params
, driver_param
);
268 SERVER_EXPORT
int jackctl_driver_params_parse(jackctl_driver
*driver_ptr
, int argc
, char* argv
[])
270 struct option
* long_options
;
271 char* options
, * options_ptr
;
275 jackctl_parameter_t
* param
= NULL
;
276 union jackctl_parameter_value value
;
282 const JSList
* driver_params
= jackctl_driver_get_parameters(driver_ptr
);
283 if (driver_params
== NULL
) {
287 jack_driver_desc_t
* desc
= jackctl_driver_get_desc(driver_ptr
);
290 if (strcmp (argv
[1], "-h") == 0 || strcmp (argv
[1], "--help") == 0) {
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
);
299 fprintf (stderr
, "Jackd: unknown option '%s' "
300 "for driver '%s'\n", argv
[2],
304 jack_log("Parameters for driver '%s' (all parameters are optional):", desc
->name
);
305 jack_print_driver_options (desc
, stdout
);
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
));
313 options_ptr
= options
;
314 for (i
= 0; i
< desc
->nparams
; i
++) {
315 sprintf(options_ptr
, "%c::", desc
->params
[i
].character
);
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
;
323 /* create the params */
326 while ((opt
= getopt_long(argc
, argv
, options
, long_options
, NULL
)) != -1) {
328 if (opt
== ':' || opt
== '?') {
330 fprintf (stderr
, "Missing option to argument '%c'\n", optopt
);
332 fprintf (stderr
, "Unknownage with option '%c'\n", optopt
);
335 fprintf (stderr
, "Options for driver '%s':\n", desc
->name
);
336 jack_print_driver_options(desc
, stderr
);
340 node_ptr
= (JSList
*)driver_params
;
342 param
= (jackctl_parameter_t
*)node_ptr
->data
;
343 if (opt
== jackctl_parameter_get_id(param
)) {
346 node_ptr
= node_ptr
->next
;
349 if (!optarg
&& optind
< argc
&&
350 strlen(argv
[optind
]) &&
351 argv
[optind
][0] != '-') {
352 optarg
= argv
[optind
];
356 switch (jackctl_parameter_get_type(param
)) {
357 case JackDriverParamInt
:
358 value
.i
= atoi(optarg
);
359 jackctl_parameter_set_value(param
, &value
);
361 case JackDriverParamUInt
:
362 value
.ui
= strtoul(optarg
, NULL
, 10);
363 jackctl_parameter_set_value(param
, &value
);
365 case JackDriverParamChar
:
367 jackctl_parameter_set_value(param
, &value
);
369 case JackDriverParamString
:
370 strncpy(value
.str
, optarg
, JACK_DRIVER_PARAM_STRING_MAX
);
371 jackctl_parameter_set_value(param
, &value
);
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 ) {
383 jackctl_parameter_set_value(param
, &value
);
387 if (jackctl_parameter_get_type(param
) == JackParamBool
) {
390 value
= jackctl_parameter_get_default_value(param
);
392 jackctl_parameter_set_value(param
, &value
);
401 jack_driver_desc_t
* jack_find_driver_descriptor (JSList
* drivers
, const char* name
)
403 jack_driver_desc_t
* desc
= 0;
406 for (node
= drivers
; node
; node
= jack_slist_next (node
)) {
407 desc
= (jack_driver_desc_t
*) node
->data
;
409 if (strcmp (desc
->name
, name
) != 0) {
419 static void* check_symbol(const char* sofile
, const char* symbol
, const char* driver_dir
, void** res_dllhandle
= NULL
)
424 sprintf(filename
, "%s/%s", driver_dir
, sofile
);
426 if ((dlhandle
= LoadDriverModule(filename
)) == NULL
) {
428 jack_error ("Could not open component .dll '%s': %ld", filename
, GetLastError());
430 jack_error ("Could not open component .so '%s': %s", filename
, dlerror());
433 res
= (void*)GetDriverProc(dlhandle
, symbol
);
435 *res_dllhandle
= dlhandle
;
437 UnloadDriverModule(dlhandle
);
444 static jack_driver_desc_t
* jack_get_descriptor (JSList
* drivers
, const char* sofile
, const char* symbol
, const char* driver_dir
)
446 jack_driver_desc_t
* descriptor
= NULL
;
447 jack_driver_desc_t
* other_descriptor
;
448 JackDriverDescFunction so_get_descriptor
= NULL
;
453 sprintf(filename
, "%s/%s", driver_dir
, sofile
);
454 so_get_descriptor
= (JackDriverDescFunction
)check_symbol(sofile
, symbol
, driver_dir
, &dlhandle
);
456 if (so_get_descriptor
== NULL
) {
457 jack_error("jack_get_descriptor : dll %s is not a driver", sofile
);
461 if ((descriptor
= so_get_descriptor ()) == NULL
) {
462 jack_error("Driver from '%s' returned NULL descriptor", filename
);
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 */
477 strncpy(descriptor
->file
, filename
, JACK_PATH_MAX
);
481 UnloadDriverModule(dlhandle
);
487 JSList
* jack_drivers_load(JSList
* drivers
)
489 //char dll_filename[512];
490 WIN32_FIND_DATA filedata
;
492 const char* ptr
= NULL
;
493 JSList
* driver_list
= NULL
;
494 jack_driver_desc_t
* desc
= NULL
;
496 char* driver_dir
= locate_driver_dir(file
, filedata
);
498 jack_error("Driver folder not found");
503 /* check the filename is of the right format */
504 if (strncmp ("jack_", filedata
.cFileName
, 5) != 0) {
508 ptr
= strrchr (filedata
.cFileName
, '.');
514 if (strncmp ("dll", ptr
, 3) != 0) {
518 /* check if dll is an internal client */
519 if (check_symbol(filedata
.cFileName
, "jack_internal_initialize", driver_dir
) != NULL
) {
523 desc
= jack_get_descriptor (drivers
, filedata
.cFileName
, "driver_get_descriptor", driver_dir
);
525 driver_list
= jack_slist_append (driver_list
, desc
);
527 jack_error ("jack_get_descriptor returns null for \'%s\'", filedata
.cFileName
);
530 } while (FindNextFile(file
, &filedata
));
533 jack_error ("Could not find any drivers in %s!", driver_dir
);
546 JSList
* jack_drivers_load (JSList
* drivers
)
548 struct dirent
* dir_entry
;
552 JSList
* driver_list
= NULL
;
553 jack_driver_desc_t
* desc
= NULL
;
555 const char* driver_dir
;
556 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
557 driver_dir
= ADDON_DIR
;
560 /* search through the driver_dir and add get descriptors
561 from the .so files in it */
562 dir_stream
= opendir (driver_dir
);
564 jack_error ("Could not open driver directory %s: %s",
565 driver_dir
, strerror (errno
));
569 while ((dir_entry
= readdir(dir_stream
))) {
571 /* check the filename is of the right format */
572 if (strncmp ("jack_", dir_entry
->d_name
, 5) != 0) {
576 ptr
= strrchr (dir_entry
->d_name
, '.');
581 if (strncmp ("so", ptr
, 2) != 0) {
585 /* check if dll is an internal client */
586 if (check_symbol(dir_entry
->d_name
, "jack_internal_initialize", driver_dir
) != NULL
) {
590 desc
= jack_get_descriptor (drivers
, dir_entry
->d_name
, "driver_get_descriptor", driver_dir
);
592 driver_list
= jack_slist_append (driver_list
, desc
);
594 jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry
->d_name
);
598 err
= closedir (dir_stream
);
600 jack_error ("Error closing driver directory %s: %s",
601 driver_dir
, strerror (errno
));
605 jack_error ("Could not find any drivers in %s!", driver_dir
);
616 JSList
* jack_internals_load(JSList
* internals
)
618 ///char dll_filename[512];
619 WIN32_FIND_DATA filedata
;
621 const char* ptr
= NULL
;
622 JSList
* driver_list
= NULL
;
623 jack_driver_desc_t
* desc
;
625 char* driver_dir
= locate_driver_dir(file
, filedata
);
627 jack_error("Driver folder not found");
633 ptr
= strrchr (filedata
.cFileName
, '.');
639 if (strncmp ("dll", ptr
, 3) != 0) {
643 /* check if dll is an internal client */
644 if (check_symbol(filedata
.cFileName
, "jack_internal_initialize", driver_dir
) == NULL
) {
648 desc
= jack_get_descriptor (internals
, filedata
.cFileName
, "jack_get_descriptor", driver_dir
);
650 driver_list
= jack_slist_append (driver_list
, desc
);
652 jack_error ("jack_get_descriptor returns null for \'%s\'", filedata
.cFileName
);
655 } while (FindNextFile(file
, &filedata
));
658 jack_error ("Could not find any internals in %s!", driver_dir
);
671 JSList
* jack_internals_load(JSList
* internals
)
673 struct dirent
* dir_entry
;
677 JSList
* driver_list
= NULL
;
678 jack_driver_desc_t
* desc
;
680 const char* driver_dir
;
681 if ((driver_dir
= getenv("JACK_DRIVER_DIR")) == 0) {
682 driver_dir
= ADDON_DIR
;
685 /* search through the driver_dir and add get descriptors
686 from the .so files in it */
687 dir_stream
= opendir (driver_dir
);
689 jack_error ("Could not open driver directory %s: %s\n",
690 driver_dir
, strerror (errno
));
694 while ((dir_entry
= readdir(dir_stream
))) {
696 ptr
= strrchr (dir_entry
->d_name
, '.');
702 if (strncmp ("so", ptr
, 2) != 0) {
706 /* check if dll is an internal client */
707 if (check_symbol(dir_entry
->d_name
, "jack_internal_initialize", driver_dir
) == NULL
) {
711 desc
= jack_get_descriptor (internals
, dir_entry
->d_name
, "jack_get_descriptor", driver_dir
);
713 driver_list
= jack_slist_append (driver_list
, desc
);
715 jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry
->d_name
);
719 err
= closedir (dir_stream
);
721 jack_error ("Error closing internal directory %s: %s\n",
722 driver_dir
, strerror (errno
));
726 jack_error ("Could not find any internals in %s!", driver_dir
);
735 Jack::JackDriverClientInterface
* JackDriverInfo::Open(jack_driver_desc_t
* driver_desc
,
736 Jack::JackLockedEngine
* engine
,
737 Jack::JackSynchro
* synchro
,
738 const JSList
* params
)
746 fHandle
= LoadDriverModule (driver_desc
->file
);
748 if (fHandle
== NULL
) {
750 if ((errstr
= GetLastError ()) != 0) {
751 jack_error ("Can't load \"%s\": %ld", driver_desc
->file
, errstr
);
753 if ((errstr
= dlerror ()) != 0) {
754 jack_error ("Can't load \"%s\": %s", driver_desc
->file
, errstr
);
758 jack_error ("Error loading driver shared object %s", driver_desc
->file
);
763 fInitialize
= (driverInitialize
)GetDriverProc(fHandle
, "driver_initialize");
766 if ((fInitialize
== NULL
) && (errstr
= GetLastError ()) != 0) {
768 if ((fInitialize
== NULL
) && (errstr
= dlerror ()) != 0) {
770 jack_error("No initialize function in shared object %s\n", driver_desc
->file
);
774 fBackend
= fInitialize(engine
, synchro
, params
);
778 JackDriverInfo::~JackDriverInfo()
782 UnloadDriverModule(fHandle
);
786 SERVER_EXPORT jack_driver_desc_t
* jack_driver_descriptor_construct(
788 jack_driver_type_t type
,
789 const char * description
,
790 jack_driver_desc_filler_t
* filler_ptr
)
793 size_t description_len
;
794 jack_driver_desc_t
* desc_ptr
;
796 name_len
= strlen(name
);
797 description_len
= strlen(description
);
799 if (name_len
> sizeof(desc_ptr
->name
) - 1 ||
800 description_len
> sizeof(desc_ptr
->desc
) - 1) {
805 desc_ptr
= (jack_driver_desc_t
*)calloc (1, sizeof (jack_driver_desc_t
));
806 if (desc_ptr
== NULL
) {
807 jack_error("Error calloc() failed to allocate memory for driver descriptor struct");
811 memcpy(desc_ptr
->name
, name
, name_len
+ 1);
812 memcpy(desc_ptr
->desc
, description
, description_len
+ 1);
814 desc_ptr
->nparams
= 0;
815 desc_ptr
->type
= type
;
817 if (filler_ptr
!= NULL
) {
818 filler_ptr
->size
= 0;
824 SERVER_EXPORT
int jack_driver_descriptor_add_parameter(
825 jack_driver_desc_t
* desc_ptr
,
826 jack_driver_desc_filler_t
* filler_ptr
,
829 jack_driver_param_type_t type
,
830 const jack_driver_param_value_t
* value_ptr
,
831 jack_driver_param_constraint_desc_t
* constraint
,
832 const char* short_desc
,
833 const char* long_desc
)
836 size_t short_desc_len
;
837 size_t long_desc_len
;
838 jack_driver_param_desc_t
* param_ptr
;
841 name_len
= strlen(name
);
842 short_desc_len
= strlen(short_desc
);
844 if (long_desc
!= NULL
) {
845 long_desc_len
= strlen(long_desc
);
847 long_desc
= short_desc
;
848 long_desc_len
= short_desc_len
;
851 if (name_len
> sizeof(param_ptr
->name
) - 1 ||
852 short_desc_len
> sizeof(param_ptr
->short_desc
) - 1 ||
853 long_desc_len
> sizeof(param_ptr
->long_desc
) - 1) {
858 if (desc_ptr
->nparams
== filler_ptr
->size
) {
859 newsize
= filler_ptr
->size
+ 20; // most drivers have less than 20 parameters
860 param_ptr
= (jack_driver_param_desc_t
*)realloc (desc_ptr
->params
, newsize
* sizeof (jack_driver_param_desc_t
));
861 if (param_ptr
== NULL
) {
862 jack_error("Error realloc() failed for parameter array of %zu elements", newsize
);
865 filler_ptr
->size
= newsize
;
866 desc_ptr
->params
= param_ptr
;
869 assert(desc_ptr
->nparams
< filler_ptr
->size
);
870 param_ptr
= desc_ptr
->params
+ desc_ptr
->nparams
;
872 memcpy(param_ptr
->name
, name
, name_len
+ 1);
873 param_ptr
->character
= character
;
874 param_ptr
->type
= type
;
875 param_ptr
->value
= *value_ptr
;
876 param_ptr
->constraint
= constraint
;
877 memcpy(param_ptr
->short_desc
, short_desc
, short_desc_len
+ 1);
878 memcpy(param_ptr
->long_desc
, long_desc
, long_desc_len
+ 1);