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.

510 lines
15KB

  1. /*
  2. Copyright (C) 2001-2005 Paul Davis
  3. Copyright (C) 2004-2006 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 ADDON_DIR
  20. #include "config.h"
  21. #endif
  22. #include "JackDriverLoader.h"
  23. #include "JackError.h"
  24. #include <getopt.h>
  25. #ifndef WIN32
  26. #include <dirent.h>
  27. #endif
  28. static void
  29. jack_print_driver_options (jack_driver_desc_t * desc, FILE *file)
  30. {
  31. unsigned long i;
  32. char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
  33. for (i = 0; i < desc->nparams; i++) {
  34. switch (desc->params[i].type) {
  35. case JackDriverParamInt:
  36. //sprintf (arg_default, "%" PRIi32, desc->params[i].value.i);
  37. sprintf (arg_default, "%" "i", desc->params[i].value.i);
  38. break;
  39. case JackDriverParamUInt:
  40. //sprintf (arg_default, "%" PRIu32, desc->params[i].value.ui);
  41. sprintf (arg_default, "%" "u", desc->params[i].value.ui);
  42. break;
  43. case JackDriverParamChar:
  44. sprintf (arg_default, "%c", desc->params[i].value.c);
  45. break;
  46. case JackDriverParamString:
  47. if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0)
  48. sprintf (arg_default, "%s", desc->params[i].value.str);
  49. else
  50. sprintf (arg_default, "none");
  51. break;
  52. case JackDriverParamBool:
  53. sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
  54. break;
  55. }
  56. fprintf (file, "\t-%c, --%s \t%s (default: %s)\n",
  57. desc->params[i].character,
  58. desc->params[i].name,
  59. desc->params[i].short_desc,
  60. arg_default);
  61. }
  62. }
  63. static void
  64. jack_print_driver_param_usage (jack_driver_desc_t * desc, unsigned long param, FILE *file)
  65. {
  66. fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
  67. desc->params[param].name, desc->name);
  68. fprintf (file, "%s\n", desc->params[param].long_desc);
  69. }
  70. EXPORT int
  71. jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr)
  72. {
  73. struct option * long_options;
  74. char * options, * options_ptr;
  75. unsigned long i;
  76. int opt;
  77. unsigned int param_index;
  78. JSList * params = NULL;
  79. jack_driver_param_t * driver_param;
  80. if (argc <= 1) {
  81. *param_ptr = NULL;
  82. return 0;
  83. }
  84. /* check for help */
  85. if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
  86. if (argc > 2) {
  87. for (i = 0; i < desc->nparams; i++) {
  88. if (strcmp (desc->params[i].name, argv[2]) == 0) {
  89. jack_print_driver_param_usage (desc, i, stdout);
  90. return 1;
  91. }
  92. }
  93. fprintf (stderr, "jackd: unknown option '%s' "
  94. "for driver '%s'\n", argv[2],
  95. desc->name);
  96. }
  97. printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name);
  98. jack_print_driver_options (desc, stdout);
  99. return 1;
  100. }
  101. /* set up the stuff for getopt */
  102. options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
  103. long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
  104. options_ptr = options;
  105. for (i = 0; i < desc->nparams; i++) {
  106. sprintf (options_ptr, "%c::", desc->params[i].character);
  107. options_ptr += 3;
  108. long_options[i].name = desc->params[i].name;
  109. long_options[i].flag = NULL;
  110. long_options[i].val = desc->params[i].character;
  111. long_options[i].has_arg = optional_argument;
  112. }
  113. /* create the params */
  114. optind = 0;
  115. opterr = 0;
  116. while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
  117. if (opt == ':' || opt == '?') {
  118. if (opt == ':') {
  119. fprintf (stderr, "Missing option to argument '%c'\n", optopt);
  120. } else {
  121. fprintf (stderr, "Unknownage with option '%c'\n", optopt);
  122. }
  123. fprintf (stderr, "Options for driver '%s':\n", desc->name);
  124. jack_print_driver_options (desc, stderr);
  125. exit (1);
  126. }
  127. for (param_index = 0; param_index < desc->nparams; param_index++) {
  128. if (opt == desc->params[param_index].character) {
  129. break;
  130. }
  131. }
  132. driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
  133. driver_param->character = desc->params[param_index].character;
  134. if (!optarg && optind < argc &&
  135. strlen(argv[optind]) &&
  136. argv[optind][0] != '-') {
  137. optarg = argv[optind];
  138. }
  139. if (optarg) {
  140. switch (desc->params[param_index].type) {
  141. case JackDriverParamInt:
  142. driver_param->value.i = atoi (optarg);
  143. break;
  144. case JackDriverParamUInt:
  145. driver_param->value.ui = strtoul (optarg, NULL, 10);
  146. break;
  147. case JackDriverParamChar:
  148. driver_param->value.c = optarg[0];
  149. break;
  150. case JackDriverParamString:
  151. strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
  152. break;
  153. case JackDriverParamBool:
  154. /*
  155. if (strcasecmp ("false", optarg) == 0 ||
  156. strcasecmp ("off", optarg) == 0 ||
  157. strcasecmp ("no", optarg) == 0 ||
  158. strcasecmp ("0", optarg) == 0 ||
  159. strcasecmp ("(null)", optarg) == 0 ) {
  160. */
  161. // steph
  162. if (strcmp ("false", optarg) == 0 ||
  163. strcmp ("off", optarg) == 0 ||
  164. strcmp ("no", optarg) == 0 ||
  165. strcmp ("0", optarg) == 0 ||
  166. strcmp ("(null)", optarg) == 0 ) {
  167. driver_param->value.i = false;
  168. } else {
  169. driver_param->value.i = true;
  170. }
  171. break;
  172. }
  173. } else {
  174. if (desc->params[param_index].type == JackDriverParamBool) {
  175. driver_param->value.i = true;
  176. } else {
  177. driver_param->value = desc->params[param_index].value;
  178. }
  179. }
  180. params = jack_slist_append (params, driver_param);
  181. }
  182. free (options);
  183. free (long_options);
  184. if (param_ptr)
  185. *param_ptr = params;
  186. return 0;
  187. }
  188. EXPORT jack_driver_desc_t *
  189. jack_find_driver_descriptor (JSList * drivers, const char * name)
  190. {
  191. jack_driver_desc_t * desc = 0;
  192. JSList * node;
  193. for (node = drivers; node; node = jack_slist_next (node)) {
  194. desc = (jack_driver_desc_t *) node->data;
  195. if (strcmp (desc->name, name) != 0) {
  196. desc = NULL;
  197. } else {
  198. break;
  199. }
  200. }
  201. return desc;
  202. }
  203. jack_driver_desc_t *
  204. jack_drivers_get_descriptor (JSList * drivers, const char * sofile)
  205. {
  206. jack_driver_desc_t * descriptor, * other_descriptor;
  207. JackDriverDescFunction so_get_descriptor = NULL;
  208. JSList * node;
  209. void * dlhandle;
  210. char * filename;
  211. #ifdef WIN32
  212. int dlerr;
  213. #else
  214. const char * dlerr;
  215. #endif
  216. int err;
  217. /*
  218. char* driver_dir;
  219. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  220. driver_dir = ADDON_DIR;
  221. }
  222. */
  223. #ifdef WIN32
  224. char* driver_dir = ADDON_DIR;
  225. if (strcmp(ADDON_DIR, "") == 0) {
  226. char temp_driver_dir1[512];
  227. char temp_driver_dir2[512];
  228. GetCurrentDirectory(512, temp_driver_dir1);
  229. sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
  230. driver_dir = temp_driver_dir2;
  231. }
  232. #else
  233. char driver_dir[512];
  234. snprintf(driver_dir, sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
  235. #endif
  236. filename = (char *)malloc(strlen (driver_dir) + 1 + strlen(sofile) + 1);
  237. sprintf (filename, "%s/%s", driver_dir, sofile);
  238. if ((dlhandle = LoadDriverModule(filename)) == NULL) {
  239. #ifdef WIN32
  240. jack_error ("could not open driver .dll '%s': %ld\n", filename, GetLastError());
  241. #else
  242. jack_error ("could not open driver .so '%s': %s\n", filename, dlerror());
  243. #endif
  244. free(filename);
  245. return NULL;
  246. }
  247. so_get_descriptor = (JackDriverDescFunction)
  248. GetProc(dlhandle, "driver_get_descriptor");
  249. #ifdef WIN32
  250. if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
  251. fprintf(stderr, "%ld\n", dlerr);
  252. #else
  253. if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
  254. fprintf(stderr, "%s\n", dlerr);
  255. #endif
  256. UnloadDriverModule(dlhandle);
  257. free(filename);
  258. return NULL;
  259. }
  260. if ((descriptor = so_get_descriptor ()) == NULL) {
  261. jack_error("driver from '%s' returned NULL descriptor\n", filename);
  262. UnloadDriverModule(dlhandle);
  263. free(filename);
  264. return NULL;
  265. }
  266. #ifdef WIN32
  267. if ((err = UnloadDriverModule(dlhandle)) == 0) {
  268. jack_error ("error closing driver .so '%s': %ld\n", filename, GetLastError ());
  269. }
  270. #else
  271. if ((err = UnloadDriverModule(dlhandle)) != 0) {
  272. jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ());
  273. }
  274. #endif
  275. /* check it doesn't exist already */
  276. for (node = drivers; node; node = jack_slist_next (node)) {
  277. other_descriptor = (jack_driver_desc_t *) node->data;
  278. if (strcmp(descriptor->name, other_descriptor->name) == 0) {
  279. jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first\n",
  280. other_descriptor->file, filename, other_descriptor->name);
  281. /* FIXME: delete the descriptor */
  282. free(filename);
  283. return NULL;
  284. }
  285. }
  286. strncpy(descriptor->file, filename, PATH_MAX);
  287. free(filename);
  288. return descriptor;
  289. }
  290. #ifdef WIN32
  291. EXPORT JSList *
  292. jack_drivers_load (JSList * drivers) {
  293. char driver_dir[512];
  294. char dll_filename[512];
  295. WIN32_FIND_DATA filedata;
  296. HANDLE file;
  297. const char * ptr = NULL;
  298. JSList * driver_list = NULL;
  299. jack_driver_desc_t * desc;
  300. GetCurrentDirectory(512, driver_dir);
  301. sprintf(dll_filename, "%s/%s", ADDON_DIR, "*.dll");
  302. file = (HANDLE )FindFirstFile(dll_filename, &filedata);
  303. if (file == INVALID_HANDLE_VALUE) {
  304. printf("error\n");
  305. return NULL;
  306. }
  307. do {
  308. ptr = strrchr (filedata.cFileName, '.');
  309. if (!ptr) {
  310. continue;
  311. }
  312. ptr++;
  313. if (strncmp ("dll", ptr, 3) != 0) {
  314. continue;
  315. }
  316. desc = jack_drivers_get_descriptor (drivers, filedata.cFileName);
  317. if (desc) {
  318. driver_list = jack_slist_append (driver_list, desc);
  319. }
  320. } while (FindNextFile(file, &filedata));
  321. if (!driver_list) {
  322. jack_error ("could not find any drivers in %s!\n", driver_dir);
  323. return NULL;
  324. }
  325. return driver_list;
  326. }
  327. #else
  328. JSList *
  329. jack_drivers_load (JSList * drivers) {
  330. struct dirent * dir_entry;
  331. DIR * dir_stream;
  332. const char * ptr;
  333. int err;
  334. JSList * driver_list = NULL;
  335. jack_driver_desc_t * desc;
  336. /*
  337. char* driver_dir;
  338. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  339. driver_dir = ADDON_DIR;
  340. }
  341. */
  342. char driver_dir[512];
  343. snprintf(driver_dir, sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
  344. /* search through the driver_dir and add get descriptors
  345. from the .so files in it */
  346. dir_stream = opendir (driver_dir);
  347. if (!dir_stream) {
  348. jack_error ("could not open driver directory %s: %s\n",
  349. driver_dir, strerror (errno));
  350. return NULL;
  351. }
  352. while ((dir_entry = readdir(dir_stream))) {
  353. /* check the filename is of the right format */
  354. if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
  355. continue;
  356. }
  357. ptr = strrchr (dir_entry->d_name, '.');
  358. if (!ptr) {
  359. continue;
  360. }
  361. ptr++;
  362. if (strncmp ("so", ptr, 2) != 0) {
  363. continue;
  364. }
  365. desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name);
  366. if (desc) {
  367. driver_list = jack_slist_append (driver_list, desc);
  368. }
  369. }
  370. err = closedir (dir_stream);
  371. if (err) {
  372. jack_error ("error closing driver directory %s: %s\n",
  373. driver_dir, strerror (errno));
  374. }
  375. if (!driver_list) {
  376. jack_error ("could not find any drivers in %s!\n", driver_dir);
  377. return NULL;
  378. }
  379. return driver_list;
  380. }
  381. #endif
  382. jack_driver_info_t *
  383. jack_load_driver (jack_driver_desc_t * driver_desc) {
  384. #ifdef WIN32
  385. int errstr;
  386. #else
  387. const char * errstr;
  388. #endif
  389. jack_driver_info_t *info;
  390. info = (jack_driver_info_t *) calloc (1, sizeof (*info));
  391. info->handle = LoadDriverModule (driver_desc->file);
  392. if (info->handle == NULL) {
  393. #ifdef WIN32
  394. if ((errstr = GetLastError ()) != 0) {
  395. jack_error ("can't load \"%s\": %ld", driver_desc->file,
  396. errstr);
  397. #else
  398. if ((errstr = dlerror ()) != 0) {
  399. jack_error ("can't load \"%s\": %s", driver_desc->file,
  400. errstr);
  401. #endif
  402. } else {
  403. jack_error ("bizarre error loading driver shared "
  404. "object %s", driver_desc->file);
  405. }
  406. goto fail;
  407. }
  408. info->initialize = (initialize)GetProc(info->handle, "driver_initialize");
  409. #ifdef WIN32
  410. if ((info->initialize == NULL) && (errstr = GetLastError ()) != 0) {
  411. #else
  412. if ((info->initialize == NULL) && (errstr = dlerror ()) != 0) {
  413. #endif
  414. jack_error ("no initialize function in shared object %s\n",
  415. driver_desc->file);
  416. goto fail;
  417. }
  418. return info;
  419. fail:
  420. if (info->handle) {
  421. UnloadDriverModule(info->handle);
  422. }
  423. free (info);
  424. return NULL;
  425. }