jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

658 lines
20KB

  1. /*
  2. Copyright (C) 2001-2005 Paul Davis
  3. Copyright (C) 2004-2008 Grame
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #if defined(HAVE_CONFIG_H)
  17. #include "config.h"
  18. #endif
  19. #ifdef WIN32
  20. #pragma warning (disable : 4786)
  21. #endif
  22. #ifndef WIN32
  23. #ifndef ADDON_DIR
  24. #include "config.h"
  25. #endif
  26. #endif
  27. #include "JackDriverLoader.h"
  28. #include "JackError.h"
  29. #include <getopt.h>
  30. #include <stdio.h>
  31. #ifndef WIN32
  32. #include <dirent.h>
  33. #endif
  34. #include <errno.h>
  35. jack_driver_desc_t * jackctl_driver_get_desc(jackctl_driver_t * driver);
  36. static void
  37. jack_print_driver_options (jack_driver_desc_t * desc, FILE *file)
  38. {
  39. unsigned long i;
  40. char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
  41. for (i = 0; i < desc->nparams; i++) {
  42. switch (desc->params[i].type) {
  43. case JackDriverParamInt:
  44. sprintf (arg_default, "%" "i", desc->params[i].value.i);
  45. break;
  46. case JackDriverParamUInt:
  47. sprintf (arg_default, "%" "u", desc->params[i].value.ui);
  48. break;
  49. case JackDriverParamChar:
  50. sprintf (arg_default, "%c", desc->params[i].value.c);
  51. break;
  52. case JackDriverParamString:
  53. if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0)
  54. sprintf (arg_default, "%s", desc->params[i].value.str);
  55. else
  56. sprintf (arg_default, "none");
  57. break;
  58. case JackDriverParamBool:
  59. sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
  60. break;
  61. }
  62. fprintf (file, "\t-%c, --%s \t%s (default: %s)\n",
  63. desc->params[i].character,
  64. desc->params[i].name,
  65. desc->params[i].short_desc,
  66. arg_default);
  67. }
  68. }
  69. static void
  70. jack_print_driver_param_usage (jack_driver_desc_t * desc, unsigned long param, FILE *file)
  71. {
  72. fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
  73. desc->params[param].name, desc->name);
  74. fprintf (file, "%s\n", desc->params[param].long_desc);
  75. }
  76. int
  77. jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr)
  78. {
  79. struct option * long_options;
  80. char * options, * options_ptr;
  81. unsigned long i;
  82. int opt;
  83. unsigned int param_index;
  84. JSList * params = NULL;
  85. jack_driver_param_t * driver_param;
  86. if (argc <= 1) {
  87. *param_ptr = NULL;
  88. return 0;
  89. }
  90. /* check for help */
  91. if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
  92. if (argc > 2) {
  93. for (i = 0; i < desc->nparams; i++) {
  94. if (strcmp (desc->params[i].name, argv[2]) == 0) {
  95. jack_print_driver_param_usage (desc, i, stdout);
  96. return 1;
  97. }
  98. }
  99. fprintf (stderr, "jackd: unknown option '%s' "
  100. "for driver '%s'\n", argv[2],
  101. desc->name);
  102. }
  103. printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name);
  104. jack_print_driver_options (desc, stdout);
  105. return 1;
  106. }
  107. /* set up the stuff for getopt */
  108. options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
  109. long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
  110. options_ptr = options;
  111. for (i = 0; i < desc->nparams; i++) {
  112. sprintf (options_ptr, "%c::", desc->params[i].character);
  113. options_ptr += 3;
  114. long_options[i].name = desc->params[i].name;
  115. long_options[i].flag = NULL;
  116. long_options[i].val = desc->params[i].character;
  117. long_options[i].has_arg = optional_argument;
  118. }
  119. /* create the params */
  120. optind = 0;
  121. opterr = 0;
  122. while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
  123. if (opt == ':' || opt == '?') {
  124. if (opt == ':') {
  125. fprintf (stderr, "Missing option to argument '%c'\n", optopt);
  126. } else {
  127. fprintf (stderr, "Unknownage with option '%c'\n", optopt);
  128. }
  129. fprintf (stderr, "Options for driver '%s':\n", desc->name);
  130. jack_print_driver_options (desc, stderr);
  131. exit (1);
  132. }
  133. for (param_index = 0; param_index < desc->nparams; param_index++) {
  134. if (opt == desc->params[param_index].character) {
  135. break;
  136. }
  137. }
  138. driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
  139. driver_param->character = desc->params[param_index].character;
  140. if (!optarg && optind < argc &&
  141. strlen(argv[optind]) &&
  142. argv[optind][0] != '-') {
  143. optarg = argv[optind];
  144. }
  145. if (optarg) {
  146. switch (desc->params[param_index].type) {
  147. case JackDriverParamInt:
  148. driver_param->value.i = atoi (optarg);
  149. break;
  150. case JackDriverParamUInt:
  151. driver_param->value.ui = strtoul (optarg, NULL, 10);
  152. break;
  153. case JackDriverParamChar:
  154. driver_param->value.c = optarg[0];
  155. break;
  156. case JackDriverParamString:
  157. strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
  158. break;
  159. case JackDriverParamBool:
  160. /*
  161. if (strcasecmp ("false", optarg) == 0 ||
  162. strcasecmp ("off", optarg) == 0 ||
  163. strcasecmp ("no", optarg) == 0 ||
  164. strcasecmp ("0", optarg) == 0 ||
  165. strcasecmp ("(null)", optarg) == 0 ) {
  166. */
  167. // steph
  168. if (strcmp ("false", optarg) == 0 ||
  169. strcmp ("off", optarg) == 0 ||
  170. strcmp ("no", optarg) == 0 ||
  171. strcmp ("0", optarg) == 0 ||
  172. strcmp ("(null)", optarg) == 0 ) {
  173. driver_param->value.i = false;
  174. } else {
  175. driver_param->value.i = true;
  176. }
  177. break;
  178. }
  179. } else {
  180. if (desc->params[param_index].type == JackDriverParamBool) {
  181. driver_param->value.i = true;
  182. } else {
  183. driver_param->value = desc->params[param_index].value;
  184. }
  185. }
  186. params = jack_slist_append (params, driver_param);
  187. }
  188. free (options);
  189. free (long_options);
  190. if (param_ptr)
  191. *param_ptr = params;
  192. return 0;
  193. }
  194. EXPORT int
  195. jackctl_parse_driver_params (jackctl_driver *driver_ptr, int argc, char* argv[])
  196. {
  197. struct option * long_options;
  198. char * options, * options_ptr;
  199. unsigned long i;
  200. int opt;
  201. JSList * node_ptr;
  202. jackctl_parameter_t * param;
  203. union jackctl_parameter_value value;
  204. if (argc <= 1)
  205. return 0;
  206. const JSList * driver_params = jackctl_driver_get_parameters(driver_ptr);
  207. if (driver_params == NULL)
  208. return 1;
  209. jack_driver_desc_t * desc = jackctl_driver_get_desc(driver_ptr);
  210. /* check for help */
  211. if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
  212. if (argc > 2) {
  213. for (i = 0; i < desc->nparams; i++) {
  214. if (strcmp (desc->params[i].name, argv[2]) == 0) {
  215. jack_print_driver_param_usage (desc, i, stdout);
  216. return 1;
  217. }
  218. }
  219. fprintf (stderr, "jackd: unknown option '%s' "
  220. "for driver '%s'\n", argv[2],
  221. desc->name);
  222. }
  223. printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name);
  224. jack_print_driver_options (desc, stdout);
  225. return 1;
  226. }
  227. /* set up the stuff for getopt */
  228. options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
  229. long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
  230. options_ptr = options;
  231. for (i = 0; i < desc->nparams; i++) {
  232. sprintf (options_ptr, "%c::", desc->params[i].character);
  233. options_ptr += 3;
  234. long_options[i].name = desc->params[i].name;
  235. long_options[i].flag = NULL;
  236. long_options[i].val = desc->params[i].character;
  237. long_options[i].has_arg = optional_argument;
  238. }
  239. /* create the params */
  240. optind = 0;
  241. opterr = 0;
  242. while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
  243. if (opt == ':' || opt == '?') {
  244. if (opt == ':') {
  245. fprintf (stderr, "Missing option to argument '%c'\n", optopt);
  246. } else {
  247. fprintf (stderr, "Unknownage with option '%c'\n", optopt);
  248. }
  249. fprintf (stderr, "Options for driver '%s':\n", desc->name);
  250. jack_print_driver_options(desc, stderr);
  251. return 1;
  252. }
  253. node_ptr = (JSList *)driver_params;
  254. while (node_ptr) {
  255. param = (jackctl_parameter_t*)node_ptr->data;
  256. if (opt == jackctl_parameter_get_id(param)) {
  257. break;
  258. }
  259. node_ptr = node_ptr->next;
  260. }
  261. if (!optarg && optind < argc &&
  262. strlen(argv[optind]) &&
  263. argv[optind][0] != '-') {
  264. optarg = argv[optind];
  265. }
  266. if (optarg) {
  267. switch (jackctl_parameter_get_type(param)) {
  268. case JackDriverParamInt:
  269. value.i = atoi (optarg);
  270. jackctl_parameter_set_value(param, &value);
  271. break;
  272. case JackDriverParamUInt:
  273. value.ui = strtoul (optarg, NULL, 10);
  274. jackctl_parameter_set_value(param, &value);
  275. break;
  276. case JackDriverParamChar:
  277. value.c = optarg[0];
  278. jackctl_parameter_set_value(param, &value);
  279. break;
  280. case JackDriverParamString:
  281. strncpy (value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
  282. jackctl_parameter_set_value(param, &value);
  283. break;
  284. case JackDriverParamBool:
  285. /*
  286. if (strcasecmp ("false", optarg) == 0 ||
  287. strcasecmp ("off", optarg) == 0 ||
  288. strcasecmp ("no", optarg) == 0 ||
  289. strcasecmp ("0", optarg) == 0 ||
  290. strcasecmp ("(null)", optarg) == 0 ) {
  291. */
  292. // steph
  293. if (strcmp ("false", optarg) == 0 ||
  294. strcmp ("off", optarg) == 0 ||
  295. strcmp ("no", optarg) == 0 ||
  296. strcmp ("0", optarg) == 0 ||
  297. strcmp ("(null)", optarg) == 0 ) {
  298. value.i = false;
  299. } else {
  300. value.i = true;
  301. }
  302. jackctl_parameter_set_value(param, &value);
  303. break;
  304. }
  305. } else {
  306. if (jackctl_parameter_get_type(param) == JackParamBool) {
  307. value.i = true;
  308. } else {
  309. value = jackctl_parameter_get_default_value(param);
  310. }
  311. jackctl_parameter_set_value(param, &value);
  312. }
  313. }
  314. free(options);
  315. free(long_options);
  316. return 0;
  317. }
  318. jack_driver_desc_t *
  319. jack_find_driver_descriptor (JSList * drivers, const char * name)
  320. {
  321. jack_driver_desc_t * desc = 0;
  322. JSList * node;
  323. for (node = drivers; node; node = jack_slist_next (node)) {
  324. desc = (jack_driver_desc_t *) node->data;
  325. if (strcmp (desc->name, name) != 0) {
  326. desc = NULL;
  327. } else {
  328. break;
  329. }
  330. }
  331. return desc;
  332. }
  333. jack_driver_desc_t *
  334. jack_drivers_get_descriptor (JSList * drivers, const char * sofile)
  335. {
  336. jack_driver_desc_t * descriptor, * other_descriptor;
  337. JackDriverDescFunction so_get_descriptor = NULL;
  338. JSList * node;
  339. void * dlhandle;
  340. char * filename;
  341. #ifdef WIN32
  342. int dlerr;
  343. #else
  344. const char * dlerr;
  345. #endif
  346. int err;
  347. const char* driver_dir;
  348. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  349. // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
  350. // for posix systems, it is absolute path of default driver dir
  351. #ifdef WIN32
  352. char temp_driver_dir1[512];
  353. char temp_driver_dir2[512];
  354. GetCurrentDirectory(512, temp_driver_dir1);
  355. sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
  356. driver_dir = temp_driver_dir2;
  357. #else
  358. driver_dir = ADDON_DIR;
  359. #endif
  360. }
  361. filename = (char *)malloc(strlen (driver_dir) + 1 + strlen(sofile) + 1);
  362. sprintf (filename, "%s/%s", driver_dir, sofile);
  363. if ((dlhandle = LoadDriverModule(filename)) == NULL) {
  364. #ifdef WIN32
  365. jack_error ("could not open driver .dll '%s': %ld\n", filename, GetLastError());
  366. #else
  367. jack_error ("could not open driver .so '%s': %s\n", filename, dlerror());
  368. #endif
  369. free(filename);
  370. return NULL;
  371. }
  372. so_get_descriptor = (JackDriverDescFunction)
  373. GetProc(dlhandle, "driver_get_descriptor");
  374. #ifdef WIN32
  375. if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
  376. jack_error("%ld", dlerr);
  377. #else
  378. if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
  379. jack_error("%s", dlerr);
  380. #endif
  381. UnloadDriverModule(dlhandle);
  382. free(filename);
  383. return NULL;
  384. }
  385. if ((descriptor = so_get_descriptor ()) == NULL) {
  386. jack_error("driver from '%s' returned NULL descriptor\n", filename);
  387. UnloadDriverModule(dlhandle);
  388. free(filename);
  389. return NULL;
  390. }
  391. #ifdef WIN32
  392. if ((err = UnloadDriverModule(dlhandle)) == 0) {
  393. jack_error ("error closing driver .so '%s': %ld\n", filename, GetLastError ());
  394. }
  395. #else
  396. if ((err = UnloadDriverModule(dlhandle)) != 0) {
  397. jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ());
  398. }
  399. #endif
  400. /* check it doesn't exist already */
  401. for (node = drivers; node; node = jack_slist_next (node)) {
  402. other_descriptor = (jack_driver_desc_t *) node->data;
  403. if (strcmp(descriptor->name, other_descriptor->name) == 0) {
  404. jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first\n",
  405. other_descriptor->file, filename, other_descriptor->name);
  406. /* FIXME: delete the descriptor */
  407. free(filename);
  408. return NULL;
  409. }
  410. }
  411. strncpy(descriptor->file, filename, PATH_MAX);
  412. free(filename);
  413. return descriptor;
  414. }
  415. #ifdef WIN32
  416. JSList *
  417. jack_drivers_load (JSList * drivers) {
  418. char * driver_dir;
  419. char driver_dir_storage[512];
  420. char dll_filename[512];
  421. WIN32_FIND_DATA filedata;
  422. HANDLE file;
  423. const char * ptr = NULL;
  424. JSList * driver_list = NULL;
  425. jack_driver_desc_t * desc;
  426. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  427. // for WIN32 ADDON_DIR is defined in JackConstants.h as relative path
  428. GetCurrentDirectory(512, driver_dir_storage);
  429. strcat(driver_dir_storage, "/");
  430. strcat(driver_dir_storage, ADDON_DIR);
  431. driver_dir = driver_dir_storage;
  432. }
  433. sprintf(dll_filename, "%s/*.dll", driver_dir);
  434. file = (HANDLE )FindFirstFile(dll_filename, &filedata);
  435. if (file == INVALID_HANDLE_VALUE) {
  436. jack_error("error");
  437. return NULL;
  438. }
  439. do {
  440. ptr = strrchr (filedata.cFileName, '.');
  441. if (!ptr) {
  442. continue;
  443. }
  444. ptr++;
  445. if (strncmp ("dll", ptr, 3) != 0) {
  446. continue;
  447. }
  448. desc = jack_drivers_get_descriptor (drivers, filedata.cFileName);
  449. if (desc) {
  450. driver_list = jack_slist_append (driver_list, desc);
  451. }
  452. } while (FindNextFile(file, &filedata));
  453. if (!driver_list) {
  454. jack_error ("could not find any drivers in %s!\n", driver_dir);
  455. return NULL;
  456. }
  457. return driver_list;
  458. }
  459. #else
  460. JSList *
  461. jack_drivers_load (JSList * drivers) {
  462. struct dirent * dir_entry;
  463. DIR * dir_stream;
  464. const char * ptr;
  465. int err;
  466. JSList * driver_list = NULL;
  467. jack_driver_desc_t * desc;
  468. const char* driver_dir;
  469. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  470. driver_dir = ADDON_DIR;
  471. }
  472. /* search through the driver_dir and add get descriptors
  473. from the .so files in it */
  474. dir_stream = opendir (driver_dir);
  475. if (!dir_stream) {
  476. jack_error ("could not open driver directory %s: %s\n",
  477. driver_dir, strerror (errno));
  478. return NULL;
  479. }
  480. while ((dir_entry = readdir(dir_stream))) {
  481. /* check the filename is of the right format */
  482. if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
  483. continue;
  484. }
  485. ptr = strrchr (dir_entry->d_name, '.');
  486. if (!ptr) {
  487. continue;
  488. }
  489. ptr++;
  490. if (strncmp ("so", ptr, 2) != 0) {
  491. continue;
  492. }
  493. desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name);
  494. if (desc) {
  495. driver_list = jack_slist_append (driver_list, desc);
  496. }
  497. }
  498. err = closedir (dir_stream);
  499. if (err) {
  500. jack_error ("error closing driver directory %s: %s\n",
  501. driver_dir, strerror (errno));
  502. }
  503. if (!driver_list) {
  504. jack_error ("could not find any drivers in %s!\n", driver_dir);
  505. return NULL;
  506. }
  507. return driver_list;
  508. }
  509. #endif
  510. jack_driver_info_t *
  511. jack_load_driver (jack_driver_desc_t * driver_desc) {
  512. #ifdef WIN32
  513. int errstr;
  514. #else
  515. const char * errstr;
  516. #endif
  517. jack_driver_info_t *info;
  518. info = (jack_driver_info_t *) calloc (1, sizeof (*info));
  519. info->handle = LoadDriverModule (driver_desc->file);
  520. if (info->handle == NULL) {
  521. #ifdef WIN32
  522. if ((errstr = GetLastError ()) != 0) {
  523. jack_error ("can't load \"%s\": %ld", driver_desc->file,
  524. errstr);
  525. #else
  526. if ((errstr = dlerror ()) != 0) {
  527. jack_error ("can't load \"%s\": %s", driver_desc->file,
  528. errstr);
  529. #endif
  530. } else {
  531. jack_error ("bizarre error loading driver shared "
  532. "object %s", driver_desc->file);
  533. }
  534. goto fail;
  535. }
  536. info->initialize = (initialize)GetProc(info->handle, "driver_initialize");
  537. #ifdef WIN32
  538. if ((info->initialize == NULL) && (errstr = GetLastError ()) != 0) {
  539. #else
  540. if ((info->initialize == NULL) && (errstr = dlerror ()) != 0) {
  541. #endif
  542. jack_error ("no initialize function in shared object %s\n",
  543. driver_desc->file);
  544. goto fail;
  545. }
  546. return info;
  547. fail:
  548. if (info->handle) {
  549. UnloadDriverModule(info->handle);
  550. }
  551. free (info);
  552. return NULL;
  553. }