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.

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