Merge pull request #23 from jackaudio/device_reservation_fixes
[jack2.git] / common / JackDriverLoader.cpp
blob488cb43f377385f592d5ba13eb8cf7b4308fcc63
1 /*
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"
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <string.h>
31 #ifndef WIN32
32 #include <dirent.h>
33 #endif
35 #ifdef WIN32
37 static char* locate_dll_driver_dir()
39 #ifdef _WIN64
40 HMODULE libjack_handle = LoadLibrary("libjackserver64.dll");
41 #else
42 HMODULE libjack_handle = LoadLibrary("libjackserver.dll");
43 #endif
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;
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;
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 ");
74 free(driver_dir);
75 return NULL;
76 } else {
77 return driver_dir;
81 #endif
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)
87 unsigned long i;
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);
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");
107 break;
108 case JackDriverParamBool:
109 sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
110 break;
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);
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;
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;
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;
145 unsigned long i;
146 int opt;
147 unsigned int param_index;
148 JSList* params = NULL;
149 jack_driver_param_t * driver_param;
151 if (argc <= 1) {
152 *param_ptr = NULL;
153 return 0;
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;
166 fprintf (stderr, "Jackd: unknown option '%s' "
167 "for driver '%s'\n", argv[2],
168 desc->name);
171 jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
172 jack_print_driver_options (desc, stdout);
173 return 1;
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);
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;
190 /* create the params */
191 optind = 0;
192 opterr = 0;
193 while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
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);
202 fprintf (stderr, "Options for driver '%s':\n", desc->name);
203 jack_print_driver_options (desc, stderr);
204 return 1;
207 for (param_index = 0; param_index < desc->nparams; param_index++) {
208 if (opt == desc->params[param_index].character) {
209 break;
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];
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;
246 break;
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;
256 params = jack_slist_append (params, driver_param);
259 free (options);
260 free (long_options);
262 if (param_ptr) {
263 *param_ptr = params;
265 return 0;
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;
272 unsigned long i;
273 int opt;
274 JSList* node_ptr;
275 jackctl_parameter_t * param = NULL;
276 union jackctl_parameter_value value;
278 if (argc <= 1) {
279 return 0;
282 const JSList* driver_params = jackctl_driver_get_parameters(driver_ptr);
283 if (driver_params == NULL) {
284 return 1;
287 jack_driver_desc_t* desc = jackctl_driver_get_desc(driver_ptr);
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;
299 fprintf (stderr, "Jackd: unknown option '%s' "
300 "for driver '%s'\n", argv[2],
301 desc->name);
304 jack_log("Parameters for driver '%s' (all parameters are optional):", desc->name);
305 jack_print_driver_options (desc, stdout);
306 return 1;
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);
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;
323 /* create the params */
324 optind = 0;
325 opterr = 0;
326 while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
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);
335 fprintf (stderr, "Options for driver '%s':\n", desc->name);
336 jack_print_driver_options(desc, stderr);
337 return 1;
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;
346 node_ptr = node_ptr->next;
349 if (!optarg && optind < argc &&
350 strlen(argv[optind]) &&
351 argv[optind][0] != '-') {
352 optarg = argv[optind];
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;
383 jackctl_parameter_set_value(param, &value);
384 break;
386 } else {
387 if (jackctl_parameter_get_type(param) == JackParamBool) {
388 value.i = true;
389 } else {
390 value = jackctl_parameter_get_default_value(param);
392 jackctl_parameter_set_value(param, &value);
396 free(options);
397 free(long_options);
398 return 0;
401 jack_driver_desc_t* jack_find_driver_descriptor (JSList * drivers, const char* name)
403 jack_driver_desc_t* desc = 0;
404 JSList* node;
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) {
410 desc = NULL;
411 } else {
412 break;
416 return desc;
419 static void* check_symbol(const char* sofile, const char* symbol, const char* driver_dir, void** res_dllhandle = NULL)
421 void* dlhandle;
422 void* res = NULL;
423 char filename[1024];
424 sprintf(filename, "%s/%s", driver_dir, sofile);
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);
441 return res;
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;
449 char filename[1024];
450 JSList* node;
451 void* dlhandle;
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);
458 goto error;
461 if ((descriptor = so_get_descriptor ()) == NULL) {
462 jack_error("Driver from '%s' returned NULL descriptor", filename);
463 goto error;
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;
477 strncpy(descriptor->file, filename, JACK_PATH_MAX);
479 error:
481 UnloadDriverModule(dlhandle);
482 return descriptor;
485 #ifdef WIN32
487 JSList * jack_drivers_load(JSList * drivers)
489 //char dll_filename[512];
490 WIN32_FIND_DATA filedata;
491 HANDLE file;
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);
497 if (!driver_dir) {
498 jack_error("Driver folder not found");
499 goto error;
502 do {
503 /* check the filename is of the right format */
504 if (strncmp ("jack_", filedata.cFileName, 5) != 0) {
505 continue;
508 ptr = strrchr (filedata.cFileName, '.');
509 if (!ptr) {
510 continue;
513 ptr++;
514 if (strncmp ("dll", ptr, 3) != 0) {
515 continue;
518 /* check if dll is an internal client */
519 if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) != NULL) {
520 continue;
523 desc = jack_get_descriptor (drivers, filedata.cFileName, "driver_get_descriptor", driver_dir);
524 if (desc) {
525 driver_list = jack_slist_append (driver_list, desc);
526 } else {
527 jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
530 } while (FindNextFile(file, &filedata));
532 if (!driver_list) {
533 jack_error ("Could not find any drivers in %s!", driver_dir);
536 error:
537 if (driver_dir) {
538 free(driver_dir);
540 FindClose(file);
541 return driver_list;
544 #else
546 JSList* jack_drivers_load (JSList * drivers)
548 struct dirent * dir_entry;
549 DIR * dir_stream;
550 const char* ptr;
551 int err;
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);
563 if (!dir_stream) {
564 jack_error ("Could not open driver directory %s: %s",
565 driver_dir, strerror (errno));
566 return NULL;
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) {
573 continue;
576 ptr = strrchr (dir_entry->d_name, '.');
577 if (!ptr) {
578 continue;
580 ptr++;
581 if (strncmp ("so", ptr, 2) != 0) {
582 continue;
585 /* check if dll is an internal client */
586 if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) != NULL) {
587 continue;
590 desc = jack_get_descriptor (drivers, dir_entry->d_name, "driver_get_descriptor", driver_dir);
591 if (desc) {
592 driver_list = jack_slist_append (driver_list, desc);
593 } else {
594 jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
598 err = closedir (dir_stream);
599 if (err) {
600 jack_error ("Error closing driver directory %s: %s",
601 driver_dir, strerror (errno));
604 if (!driver_list) {
605 jack_error ("Could not find any drivers in %s!", driver_dir);
606 return NULL;
609 return driver_list;
612 #endif
614 #ifdef WIN32
616 JSList* jack_internals_load(JSList * internals)
618 ///char dll_filename[512];
619 WIN32_FIND_DATA filedata;
620 HANDLE file;
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);
626 if (!driver_dir) {
627 jack_error("Driver folder not found");
628 goto error;
631 do {
633 ptr = strrchr (filedata.cFileName, '.');
634 if (!ptr) {
635 continue;
638 ptr++;
639 if (strncmp ("dll", ptr, 3) != 0) {
640 continue;
643 /* check if dll is an internal client */
644 if (check_symbol(filedata.cFileName, "jack_internal_initialize", driver_dir) == NULL) {
645 continue;
648 desc = jack_get_descriptor (internals, filedata.cFileName, "jack_get_descriptor", driver_dir);
649 if (desc) {
650 driver_list = jack_slist_append (driver_list, desc);
651 } else {
652 jack_error ("jack_get_descriptor returns null for \'%s\'", filedata.cFileName);
655 } while (FindNextFile(file, &filedata));
657 if (!driver_list) {
658 jack_error ("Could not find any internals in %s!", driver_dir);
661 error:
662 if (driver_dir) {
663 free(driver_dir);
665 FindClose(file);
666 return driver_list;
669 #else
671 JSList* jack_internals_load(JSList * internals)
673 struct dirent * dir_entry;
674 DIR * dir_stream;
675 const char* ptr;
676 int err;
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);
688 if (!dir_stream) {
689 jack_error ("Could not open driver directory %s: %s\n",
690 driver_dir, strerror (errno));
691 return NULL;
694 while ((dir_entry = readdir(dir_stream))) {
696 ptr = strrchr (dir_entry->d_name, '.');
697 if (!ptr) {
698 continue;
701 ptr++;
702 if (strncmp ("so", ptr, 2) != 0) {
703 continue;
706 /* check if dll is an internal client */
707 if (check_symbol(dir_entry->d_name, "jack_internal_initialize", driver_dir) == NULL) {
708 continue;
711 desc = jack_get_descriptor (internals, dir_entry->d_name, "jack_get_descriptor", driver_dir);
712 if (desc) {
713 driver_list = jack_slist_append (driver_list, desc);
714 } else {
715 jack_error ("jack_get_descriptor returns null for \'%s\'", dir_entry->d_name);
719 err = closedir (dir_stream);
720 if (err) {
721 jack_error ("Error closing internal directory %s: %s\n",
722 driver_dir, strerror (errno));
725 if (!driver_list) {
726 jack_error ("Could not find any internals in %s!", driver_dir);
727 return NULL;
730 return driver_list;
733 #endif
735 Jack::JackDriverClientInterface* JackDriverInfo::Open(jack_driver_desc_t* driver_desc,
736 Jack::JackLockedEngine* engine,
737 Jack::JackSynchro* synchro,
738 const JSList* params)
740 #ifdef WIN32
741 int errstr;
742 #else
743 const char* errstr;
744 #endif
746 fHandle = LoadDriverModule (driver_desc->file);
748 if (fHandle == NULL) {
749 #ifdef WIN32
750 if ((errstr = GetLastError ()) != 0) {
751 jack_error ("Can't load \"%s\": %ld", driver_desc->file, errstr);
752 #else
753 if ((errstr = dlerror ()) != 0) {
754 jack_error ("Can't load \"%s\": %s", driver_desc->file, errstr);
755 #endif
757 } else {
758 jack_error ("Error loading driver shared object %s", driver_desc->file);
760 return NULL;
763 fInitialize = (driverInitialize)GetDriverProc(fHandle, "driver_initialize");
765 #ifdef WIN32
766 if ((fInitialize == NULL) && (errstr = GetLastError ()) != 0) {
767 #else
768 if ((fInitialize == NULL) && (errstr = dlerror ()) != 0) {
769 #endif
770 jack_error("No initialize function in shared object %s\n", driver_desc->file);
771 return NULL;
774 fBackend = fInitialize(engine, synchro, params);
775 return fBackend;
778 JackDriverInfo::~JackDriverInfo()
780 delete fBackend;
781 if (fHandle) {
782 UnloadDriverModule(fHandle);
786 SERVER_EXPORT jack_driver_desc_t* jack_driver_descriptor_construct(
787 const char * name,
788 jack_driver_type_t type,
789 const char * description,
790 jack_driver_desc_filler_t * filler_ptr)
792 size_t name_len;
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) {
801 assert(false);
802 return 0;
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");
808 return 0;
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;
821 return desc_ptr;
824 SERVER_EXPORT int jack_driver_descriptor_add_parameter(
825 jack_driver_desc_t* desc_ptr,
826 jack_driver_desc_filler_t * filler_ptr,
827 const char* name,
828 char character,
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)
835 size_t name_len;
836 size_t short_desc_len;
837 size_t long_desc_len;
838 jack_driver_param_desc_t * param_ptr;
839 size_t newsize;
841 name_len = strlen(name);
842 short_desc_len = strlen(short_desc);
844 if (long_desc != NULL) {
845 long_desc_len = strlen(long_desc);
846 } else {
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) {
854 assert(false);
855 return 0;
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);
863 return false;
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);
880 desc_ptr->nparams++;
881 return true;