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.

654 lines
19KB

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