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.

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