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