jack1 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.

338 lines
8.5KB

  1. /*
  2. Copyright (C) 2003 Robert Ham <rah@bash.sh>
  3. Copyright (C) 2001 Paul Davis
  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. $Id$
  16. */
  17. #include <math.h>
  18. #include <stdio.h>
  19. #include <memory.h>
  20. #include <unistd.h>
  21. #include <stdlib.h>
  22. #include <errno.h>
  23. #include <stdarg.h>
  24. #include <getopt.h>
  25. #include <jack/types.h>
  26. #include <jack/internal.h>
  27. #include <jack/engine.h>
  28. #include <jack/time.h>
  29. #include "dummy_driver.h"
  30. #undef DEBUG_WAKEUP
  31. static int
  32. dummy_driver_audio_start (dummy_driver_t *driver)
  33. {
  34. return 0;
  35. }
  36. static int
  37. dummy_driver_audio_stop (dummy_driver_t *driver)
  38. {
  39. return 0;
  40. }
  41. static jack_nframes_t
  42. dummy_driver_wait (dummy_driver_t *driver, int extra_fd, int *status,
  43. float *delayed_usecs)
  44. {
  45. jack_time_t starting_time = jack_get_microseconds();
  46. jack_time_t processing_time = (driver->last_wait_ust?
  47. starting_time - driver->last_wait_ust: 0);
  48. jack_time_t sleeping_time = driver->wait_time - processing_time;
  49. /* JOQ: usleep() is inaccurate for small buffer sizes with Linux
  50. * 2.4. I suspect it can't wait for less than one (or maybe even
  51. * two) scheduler timeslices. Linux 2.6 is probably better. */
  52. if (sleeping_time > 0)
  53. usleep (sleeping_time);
  54. driver->last_wait_ust = jack_get_microseconds ();
  55. driver->engine->transport_cycle_start (driver->engine, driver->last_wait_ust);
  56. *status = 0;
  57. *delayed_usecs = driver->last_wait_ust - starting_time - sleeping_time;
  58. return driver->period_size;
  59. }
  60. static int
  61. dummy_driver_null_cycle (dummy_driver_t* driver, jack_nframes_t nframes)
  62. {
  63. return 0;
  64. }
  65. static int
  66. dummy_driver_read (dummy_driver_t *driver, jack_nframes_t nframes)
  67. {
  68. return 0;
  69. }
  70. static int
  71. dummy_driver_write (dummy_driver_t* driver, jack_nframes_t nframes)
  72. {
  73. return 0;
  74. }
  75. static int
  76. dummy_driver_attach (dummy_driver_t *driver, jack_engine_t *engine)
  77. {
  78. jack_port_t * port;
  79. char buf[32];
  80. unsigned int chn;
  81. int port_flags;
  82. driver->engine = engine;
  83. driver->engine->set_buffer_size (engine, driver->period_size);
  84. driver->engine->set_sample_rate (engine, driver->sample_rate);
  85. port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal;
  86. for (chn = 0; chn < driver->capture_channels; chn++)
  87. {
  88. snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1);
  89. port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
  90. if (!port)
  91. {
  92. jack_error ("DUMMY: cannot register port for %s", buf);
  93. break;
  94. }
  95. driver->capture_ports = jack_slist_append (driver->capture_ports, port);
  96. }
  97. port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal;
  98. for (chn = 0; chn < driver->playback_channels; chn++)
  99. {
  100. snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1);
  101. port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
  102. if (!port)
  103. {
  104. jack_error ("DUMMY: cannot register port for %s", buf);
  105. break;
  106. }
  107. driver->playback_ports = jack_slist_append (driver->playback_ports, port);
  108. }
  109. jack_activate (driver->client);
  110. return 0;
  111. }
  112. static void
  113. dummy_driver_detach (dummy_driver_t *driver, jack_engine_t *engine)
  114. {
  115. JSList * node;
  116. if (driver->engine == 0)
  117. return;
  118. for (node = driver->capture_ports; node; node = jack_slist_next (node))
  119. jack_port_unregister (driver->client, ((jack_port_t *) node->data));
  120. jack_slist_free (driver->capture_ports);
  121. driver->capture_ports = NULL;
  122. for (node = driver->playback_ports; node; node = jack_slist_next (node))
  123. jack_port_unregister (driver->client, ((jack_port_t *) node->data));
  124. jack_slist_free (driver->playback_ports);
  125. driver->playback_ports = NULL;
  126. driver->engine = NULL;
  127. }
  128. static void
  129. dummy_driver_delete (dummy_driver_t *driver)
  130. {
  131. free (driver);
  132. }
  133. static jack_driver_t *
  134. dummy_driver_new (jack_client_t * client,
  135. char *name,
  136. unsigned int capture_ports,
  137. unsigned int playback_ports,
  138. jack_nframes_t sample_rate,
  139. jack_nframes_t period_size,
  140. unsigned long wait_time)
  141. {
  142. dummy_driver_t * driver;
  143. printf ("creating dummy driver ... %s|%" PRIu32 "|%" PRIu32
  144. "|%lu|%u|%u\n", name, sample_rate, period_size, wait_time,
  145. capture_ports, playback_ports);
  146. driver = (dummy_driver_t *) calloc (1, sizeof (dummy_driver_t));
  147. jack_driver_init ((jack_driver_t *) driver);
  148. driver->attach = (JackDriverAttachFunction) dummy_driver_attach;
  149. driver->detach = (JackDriverDetachFunction) dummy_driver_detach;
  150. driver->wait = (JackDriverWaitFunction) dummy_driver_wait;
  151. driver->read = (JackDriverReadFunction) dummy_driver_read;
  152. driver->write = (JackDriverReadFunction) dummy_driver_write;
  153. driver->null_cycle = (JackDriverNullCycleFunction) dummy_driver_null_cycle;
  154. driver->start = (JackDriverStartFunction) dummy_driver_audio_start;
  155. driver->stop = (JackDriverStopFunction) dummy_driver_audio_stop;
  156. driver->period_usecs =
  157. (jack_time_t) floor ((((float) period_size) / sample_rate) * 1000000.0f);
  158. driver->sample_rate = sample_rate;
  159. driver->period_size = period_size;
  160. driver->wait_time = wait_time;
  161. driver->last_wait_ust = 0;
  162. driver->capture_channels = capture_ports;
  163. driver->capture_ports = NULL;
  164. driver->playback_channels = playback_ports;
  165. driver->playback_ports = NULL;
  166. driver->client = client;
  167. driver->engine = NULL;
  168. return (jack_driver_t *) driver;
  169. }
  170. static void
  171. dummy_usage ()
  172. {
  173. fprintf (stderr, "\n"
  174. "dummy driver arguments:\n"
  175. " -h,--help \tprint this message\n"
  176. " -r,--rate <n> \tsample rate (default: 48000)\n"
  177. " -p,--period <n> \tframes per period (default: 1024)\n"
  178. " -C,--capture <n> \tnumber of capture ports (default: 2)\n"
  179. " -P,--playback <n> \tnumber of playback ports (default: 2)\n"
  180. " -w,--wait <usecs> \tnumber of usecs to wait between engine processes (default: 21333)\n"
  181. "\n");
  182. }
  183. static void
  184. dummy_error (char *type, char *value)
  185. {
  186. fprintf (stderr, "dummy driver: unknown %s: `%s'\n", type, value);
  187. dummy_usage();
  188. }
  189. /* DRIVER "PLUGIN" INTERFACE */
  190. const char driver_client_name[] = "dummy_pcm";
  191. jack_driver_t *
  192. driver_initialize (jack_client_t *client, int argc, char **argv)
  193. {
  194. jack_nframes_t sample_rate = 48000;
  195. jack_nframes_t period_size = 1024;
  196. unsigned int capture_ports = 2;
  197. unsigned int playback_ports = 2;
  198. int wait_time_set = 0;
  199. unsigned long wait_time;
  200. int opt;
  201. char optstring[2]; /* string made from opt char */
  202. struct option long_options[] =
  203. {
  204. { "help", no_argument, NULL, 'h' },
  205. { "rate", required_argument, NULL, 'r' },
  206. { "period", required_argument, NULL, 'p' },
  207. { "capture", required_argument, NULL, 'C' },
  208. { "playback", required_argument, NULL, 'P' },
  209. { "wait", required_argument, NULL, 'w' },
  210. { 0, 0, 0, 0 }
  211. };
  212. /*
  213. * Setting optind back to zero is a hack to reinitialize a new
  214. * getopts() loop. See declaration in <getopt.h>.
  215. */
  216. optind = 0;
  217. opterr = 0;
  218. while ((opt = getopt_long(argc, argv, "C::P::p:r:w:h",
  219. long_options, NULL))
  220. != EOF) {
  221. switch (opt) {
  222. case 'C':
  223. capture_ports = atoi (optarg);
  224. break;
  225. case 'P':
  226. playback_ports = atoi (optarg);
  227. break;
  228. case 'p':
  229. period_size = atoi(optarg);
  230. break;
  231. case 'r':
  232. sample_rate = atoi(optarg);
  233. break;
  234. case 'w':
  235. wait_time = strtoul(optarg, NULL, 10);
  236. wait_time_set = 1;
  237. break;
  238. case 'h':
  239. dummy_usage();
  240. return NULL;
  241. /* the rest is error handling: */
  242. case 1: /* not an option */
  243. dummy_error("parameter", optarg);
  244. return NULL;
  245. default: /* unrecognized option */
  246. optstring[0] = (char) optopt;
  247. optstring[1] = '\0';
  248. dummy_error("option", optstring);
  249. return NULL;
  250. }
  251. }
  252. if (!wait_time_set)
  253. wait_time = (((float)period_size) / ((float)sample_rate)) * 1000000.0;
  254. return dummy_driver_new (client, "dummy_pcm", capture_ports,
  255. playback_ports, sample_rate, period_size,
  256. wait_time);
  257. }
  258. void
  259. driver_finish (jack_driver_t *driver)
  260. {
  261. dummy_driver_delete ((dummy_driver_t *) driver);
  262. }