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