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.

512 lines
15KB

  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. static void
  31. jack_print_driver_options (jack_driver_desc_t * desc, FILE *file)
  32. {
  33. unsigned long i;
  34. char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
  35. for (i = 0; i < desc->nparams; i++) {
  36. switch (desc->params[i].type) {
  37. case JackDriverParamInt:
  38. //sprintf (arg_default, "%" PRIi32, desc->params[i].value.i);
  39. sprintf (arg_default, "%" "i", desc->params[i].value.i);
  40. break;
  41. case JackDriverParamUInt:
  42. //sprintf (arg_default, "%" PRIu32, desc->params[i].value.ui);
  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 jack_driver_desc_t *
  191. jack_find_driver_descriptor (JSList * drivers, const char * name)
  192. {
  193. jack_driver_desc_t * desc = 0;
  194. JSList * node;
  195. for (node = drivers; node; node = jack_slist_next (node)) {
  196. desc = (jack_driver_desc_t *) node->data;
  197. if (strcmp (desc->name, name) != 0) {
  198. desc = NULL;
  199. } else {
  200. break;
  201. }
  202. }
  203. return desc;
  204. }
  205. jack_driver_desc_t *
  206. jack_drivers_get_descriptor (JSList * drivers, const char * sofile)
  207. {
  208. jack_driver_desc_t * descriptor, * other_descriptor;
  209. JackDriverDescFunction so_get_descriptor = NULL;
  210. JSList * node;
  211. void * dlhandle;
  212. char * filename;
  213. #ifdef WIN32
  214. int dlerr;
  215. #else
  216. const char * dlerr;
  217. #endif
  218. int err;
  219. /*
  220. char* driver_dir;
  221. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  222. driver_dir = ADDON_DIR;
  223. }
  224. */
  225. #ifdef WIN32
  226. char* driver_dir = ADDON_DIR;
  227. if (strcmp(ADDON_DIR, "") == 0) {
  228. char temp_driver_dir1[512];
  229. char temp_driver_dir2[512];
  230. GetCurrentDirectory(512, temp_driver_dir1);
  231. sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
  232. driver_dir = temp_driver_dir2;
  233. }
  234. #else
  235. char driver_dir[512];
  236. snprintf(driver_dir, sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
  237. #endif
  238. filename = (char *)malloc(strlen (driver_dir) + 1 + strlen(sofile) + 1);
  239. sprintf (filename, "%s/%s", driver_dir, sofile);
  240. if ((dlhandle = LoadDriverModule(filename)) == NULL) {
  241. #ifdef WIN32
  242. jack_error ("could not open driver .dll '%s': %ld\n", filename, GetLastError());
  243. #else
  244. jack_error ("could not open driver .so '%s': %s\n", filename, dlerror());
  245. #endif
  246. free(filename);
  247. return NULL;
  248. }
  249. so_get_descriptor = (JackDriverDescFunction)
  250. GetProc(dlhandle, "driver_get_descriptor");
  251. #ifdef WIN32
  252. if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
  253. fprintf(stderr, "%ld\n", dlerr);
  254. #else
  255. if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
  256. fprintf(stderr, "%s\n", dlerr);
  257. #endif
  258. UnloadDriverModule(dlhandle);
  259. free(filename);
  260. return NULL;
  261. }
  262. if ((descriptor = so_get_descriptor ()) == NULL) {
  263. jack_error("driver from '%s' returned NULL descriptor\n", filename);
  264. UnloadDriverModule(dlhandle);
  265. free(filename);
  266. return NULL;
  267. }
  268. #ifdef WIN32
  269. if ((err = UnloadDriverModule(dlhandle)) == 0) {
  270. jack_error ("error closing driver .so '%s': %ld\n", filename, GetLastError ());
  271. }
  272. #else
  273. if ((err = UnloadDriverModule(dlhandle)) != 0) {
  274. jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ());
  275. }
  276. #endif
  277. /* check it doesn't exist already */
  278. for (node = drivers; node; node = jack_slist_next (node)) {
  279. other_descriptor = (jack_driver_desc_t *) node->data;
  280. if (strcmp(descriptor->name, other_descriptor->name) == 0) {
  281. jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first\n",
  282. other_descriptor->file, filename, other_descriptor->name);
  283. /* FIXME: delete the descriptor */
  284. free(filename);
  285. return NULL;
  286. }
  287. }
  288. strncpy(descriptor->file, filename, PATH_MAX);
  289. free(filename);
  290. return descriptor;
  291. }
  292. #ifdef WIN32
  293. EXPORT JSList *
  294. jack_drivers_load (JSList * drivers) {
  295. char driver_dir[512];
  296. char dll_filename[512];
  297. WIN32_FIND_DATA filedata;
  298. HANDLE file;
  299. const char * ptr = NULL;
  300. JSList * driver_list = NULL;
  301. jack_driver_desc_t * desc;
  302. GetCurrentDirectory(512, driver_dir);
  303. sprintf(dll_filename, "%s/%s", ADDON_DIR, "*.dll");
  304. file = (HANDLE )FindFirstFile(dll_filename, &filedata);
  305. if (file == INVALID_HANDLE_VALUE) {
  306. printf("error\n");
  307. return NULL;
  308. }
  309. do {
  310. ptr = strrchr (filedata.cFileName, '.');
  311. if (!ptr) {
  312. continue;
  313. }
  314. ptr++;
  315. if (strncmp ("dll", ptr, 3) != 0) {
  316. continue;
  317. }
  318. desc = jack_drivers_get_descriptor (drivers, filedata.cFileName);
  319. if (desc) {
  320. driver_list = jack_slist_append (driver_list, desc);
  321. }
  322. } while (FindNextFile(file, &filedata));
  323. if (!driver_list) {
  324. jack_error ("could not find any drivers in %s!\n", driver_dir);
  325. return NULL;
  326. }
  327. return driver_list;
  328. }
  329. #else
  330. JSList *
  331. jack_drivers_load (JSList * drivers) {
  332. struct dirent * dir_entry;
  333. DIR * dir_stream;
  334. const char * ptr;
  335. int err;
  336. JSList * driver_list = NULL;
  337. jack_driver_desc_t * desc;
  338. /*
  339. char* driver_dir;
  340. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  341. driver_dir = ADDON_DIR;
  342. }
  343. */
  344. char driver_dir[512];
  345. snprintf(driver_dir, sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
  346. /* search through the driver_dir and add get descriptors
  347. from the .so files in it */
  348. dir_stream = opendir (driver_dir);
  349. if (!dir_stream) {
  350. jack_error ("could not open driver directory %s: %s\n",
  351. driver_dir, strerror (errno));
  352. return NULL;
  353. }
  354. while ((dir_entry = readdir(dir_stream))) {
  355. /* check the filename is of the right format */
  356. if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
  357. continue;
  358. }
  359. ptr = strrchr (dir_entry->d_name, '.');
  360. if (!ptr) {
  361. continue;
  362. }
  363. ptr++;
  364. if (strncmp ("so", ptr, 2) != 0) {
  365. continue;
  366. }
  367. desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name);
  368. if (desc) {
  369. driver_list = jack_slist_append (driver_list, desc);
  370. }
  371. }
  372. err = closedir (dir_stream);
  373. if (err) {
  374. jack_error ("error closing driver directory %s: %s\n",
  375. driver_dir, strerror (errno));
  376. }
  377. if (!driver_list) {
  378. jack_error ("could not find any drivers in %s!\n", driver_dir);
  379. return NULL;
  380. }
  381. return driver_list;
  382. }
  383. #endif
  384. jack_driver_info_t *
  385. jack_load_driver (jack_driver_desc_t * driver_desc) {
  386. #ifdef WIN32
  387. int errstr;
  388. #else
  389. const char * errstr;
  390. #endif
  391. jack_driver_info_t *info;
  392. info = (jack_driver_info_t *) calloc (1, sizeof (*info));
  393. info->handle = LoadDriverModule (driver_desc->file);
  394. if (info->handle == NULL) {
  395. #ifdef WIN32
  396. if ((errstr = GetLastError ()) != 0) {
  397. jack_error ("can't load \"%s\": %ld", driver_desc->file,
  398. errstr);
  399. #else
  400. if ((errstr = dlerror ()) != 0) {
  401. jack_error ("can't load \"%s\": %s", driver_desc->file,
  402. errstr);
  403. #endif
  404. } else {
  405. jack_error ("bizarre error loading driver shared "
  406. "object %s", driver_desc->file);
  407. }
  408. goto fail;
  409. }
  410. info->initialize = (initialize)GetProc(info->handle, "driver_initialize");
  411. #ifdef WIN32
  412. if ((info->initialize == NULL) && (errstr = GetLastError ()) != 0) {
  413. #else
  414. if ((info->initialize == NULL) && (errstr = dlerror ()) != 0) {
  415. #endif
  416. jack_error ("no initialize function in shared object %s\n",
  417. driver_desc->file);
  418. goto fail;
  419. }
  420. return info;
  421. fail:
  422. if (info->handle) {
  423. UnloadDriverModule(info->handle);
  424. }
  425. free (info);
  426. return NULL;
  427. }