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.

551 lines
17KB

  1. /** @file simple_client.c
  2. *
  3. * @brief This simple client demonstrates the basic features of JACK
  4. * as they would be used by many applications.
  5. */
  6. #include <stdio.h>
  7. #include <errno.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <alloca.h>
  12. #include <math.h>
  13. #include <jack/jack.h>
  14. #include <jack/jslist.h>
  15. #define ALSA_PCM_OLD_HW_PARAMS_API
  16. #define ALSA_PCM_OLD_SW_PARAMS_API
  17. #include "alsa/asoundlib.h"
  18. #include <samplerate.h>
  19. typedef signed short ALSASAMPLE;
  20. // Here are the lists of the jack ports...
  21. JSList *capture_ports = NULL;
  22. JSList *capture_srcs = NULL;
  23. JSList *playback_ports = NULL;
  24. JSList *playback_srcs = NULL;
  25. jack_client_t *client;
  26. // TODO: make the sample format configurable soon...
  27. snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */
  28. snd_pcm_t *alsa_handle;
  29. int jack_sample_rate;
  30. double current_resample_factor = 1.0;
  31. // ------------------------------------------------------ commandline parameters
  32. int sample_rate = 0; /* stream rate */
  33. int num_channels = 2; /* count of channels */
  34. int period_size = 1024;
  35. int num_periods = 2;
  36. int target_delay = 0; /* the delay which the program should try to approach. */
  37. int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */
  38. int catch_factor = 1000;
  39. // Debug stuff:
  40. int print_counter = 10;
  41. // Alsa stuff... i dont want to touch this bullshit in the next years.... please...
  42. static int xrun_recovery(snd_pcm_t *handle, int err)
  43. {
  44. //printf( "xrun !!!....\n" );
  45. if (err == -EPIPE) { /* under-run */
  46. err = snd_pcm_prepare(handle);
  47. if (err < 0)
  48. printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
  49. return 0;
  50. } else if (err == -ESTRPIPE) {
  51. while ((err = snd_pcm_resume(handle)) == -EAGAIN)
  52. sleep(1); /* wait until the suspend flag is released */
  53. if (err < 0) {
  54. err = snd_pcm_prepare(handle);
  55. if (err < 0)
  56. printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
  57. }
  58. return 0;
  59. }
  60. return err;
  61. }
  62. static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods )
  63. {
  64. int err, dir = 0;
  65. /* choose all parameters */
  66. err = snd_pcm_hw_params_any(handle, params);
  67. if (err < 0) {
  68. printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
  69. return err;
  70. }
  71. /* set the interleaved read/write format */
  72. err = snd_pcm_hw_params_set_access(handle, params, access);
  73. if (err < 0) {
  74. printf("Access type not available for playback: %s\n", snd_strerror(err));
  75. return err;
  76. }
  77. /* set the sample format */
  78. err = snd_pcm_hw_params_set_format(handle, params, format);
  79. if (err < 0) {
  80. printf("Sample format not available for playback: %s\n", snd_strerror(err));
  81. return err;
  82. }
  83. /* set the count of channels */
  84. err = snd_pcm_hw_params_set_channels(handle, params, channels);
  85. if (err < 0) {
  86. printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err));
  87. return err;
  88. }
  89. /* set the stream rate */
  90. err = snd_pcm_hw_params_set_rate_near(handle, params, rate, 0);
  91. if (err < 0) {
  92. printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
  93. return err;
  94. }
  95. if (err != rate) {
  96. printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
  97. return -EINVAL;
  98. }
  99. /* set the buffer time */
  100. err = snd_pcm_hw_params_set_buffer_time_near(handle, params, 1000000 * period * nperiods / rate, &dir);
  101. if (err < 0) {
  102. printf("Unable to set buffer time %i for playback: %s\n", 1000000*period*nperiods / rate, snd_strerror(err));
  103. return err;
  104. }
  105. if ( snd_pcm_hw_params_get_buffer_size(params) != nperiods * period ) {
  106. printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) snd_pcm_hw_params_get_buffer_size(params) );
  107. }
  108. /* set the period time */
  109. err = snd_pcm_hw_params_set_period_time_near(handle, params, 1000000 * period / rate, &dir);
  110. if (err < 0) {
  111. printf("Unable to set period time %i for playback: %s\n", 1000000*period / rate, snd_strerror(err));
  112. return err;
  113. }
  114. int ps = snd_pcm_hw_params_get_period_size(params, NULL );
  115. if ( ps != period ) {
  116. printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, ps );
  117. }
  118. /* write the parameters to device */
  119. err = snd_pcm_hw_params(handle, params);
  120. if (err < 0) {
  121. printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
  122. return err;
  123. }
  124. return 0;
  125. }
  126. static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period, int nperiods)
  127. {
  128. int err;
  129. /* get the current swparams */
  130. err = snd_pcm_sw_params_current(handle, swparams);
  131. if (err < 0) {
  132. printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err));
  133. return err;
  134. }
  135. /* start the transfer when the buffer is full */
  136. err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period );
  137. if (err < 0) {
  138. printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
  139. return err;
  140. }
  141. err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 );
  142. if (err < 0) {
  143. printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
  144. return err;
  145. }
  146. /* allow the transfer when at least period_size samples can be processed */
  147. err = snd_pcm_sw_params_set_avail_min(handle, swparams, 1 );
  148. if (err < 0) {
  149. printf("Unable to set avail min for capture: %s\n", snd_strerror(err));
  150. return err;
  151. }
  152. /* align all transfers to 1 sample */
  153. err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
  154. if (err < 0) {
  155. printf("Unable to set transfer align for capture: %s\n", snd_strerror(err));
  156. return err;
  157. }
  158. /* write the parameters to the playback device */
  159. err = snd_pcm_sw_params(handle, swparams);
  160. if (err < 0) {
  161. printf("Unable to set sw params for capture: %s\n", snd_strerror(err));
  162. return err;
  163. }
  164. return 0;
  165. }
  166. // ok... i only need this function to communicate with the alsa bloat api...
  167. static snd_pcm_t *open_audiofd( char *device_name, int capture, int rate, int channels, int period, int nperiods )
  168. {
  169. int err;
  170. snd_pcm_t *handle;
  171. snd_pcm_hw_params_t *hwparams;
  172. snd_pcm_sw_params_t *swparams;
  173. snd_pcm_hw_params_alloca(&hwparams);
  174. snd_pcm_sw_params_alloca(&swparams);
  175. if ((err = snd_pcm_open(&(handle), device_name, capture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK )) < 0) {
  176. printf("Capture open error: %s\n", snd_strerror(err));
  177. return NULL;
  178. }
  179. if ((err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED, rate, channels, period, nperiods )) < 0) {
  180. printf("Setting of hwparams failed: %s\n", snd_strerror(err));
  181. return NULL;
  182. }
  183. if ((err = set_swparams(handle, swparams, period, nperiods)) < 0) {
  184. printf("Setting of swparams failed: %s\n", snd_strerror(err));
  185. return NULL;
  186. }
  187. //snd_pcm_start( handle );
  188. //snd_pcm_wait( handle, 200 );
  189. int num_null_samples = nperiods * period * channels;
  190. ALSASAMPLE *tmp = alloca( num_null_samples * sizeof( ALSASAMPLE ) );
  191. memset( tmp, 0, num_null_samples * sizeof( ALSASAMPLE ) );
  192. snd_pcm_writei( handle, tmp, num_null_samples );
  193. return handle;
  194. }
  195. /**
  196. * The process callback for this JACK application.
  197. * It is called by JACK at the appropriate times.
  198. */
  199. int process (jack_nframes_t nframes, void *arg)
  200. {
  201. ALSASAMPLE *outbuf;
  202. float *floatbuf, *resampbuf;
  203. int rlen;
  204. int err;
  205. snd_pcm_sframes_t delay;
  206. snd_pcm_delay( alsa_handle, &delay );
  207. // Do it the hard way.
  208. // this is for compensating xruns etc...
  209. if (delay > (target_delay + max_diff)) {
  210. snd_pcm_rewind( alsa_handle, delay - target_delay );
  211. //snd_pcm_writei( alsa_handle, tmp, target_delay-t_delay );
  212. printf( "delay = %d", (int) delay );
  213. snd_pcm_delay( alsa_handle, &delay );
  214. printf( "... and delay = %d\n", (int) delay );
  215. delay = target_delay;
  216. // XXX: at least set it to that value.
  217. current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
  218. }
  219. if (delay < (target_delay - max_diff)) {
  220. ALSASAMPLE *tmp = alloca( (target_delay - delay) * sizeof( ALSASAMPLE ) * num_channels );
  221. memset( tmp, 0, sizeof( ALSASAMPLE ) * num_channels * (target_delay - delay) );
  222. snd_pcm_writei( alsa_handle, tmp, target_delay - delay );
  223. printf( "delay = %d", (int) delay );
  224. snd_pcm_delay( alsa_handle, &delay );
  225. printf( "... and delay = %d\n", (int) delay );
  226. delay = target_delay;
  227. // XXX: at least set it to that value.
  228. current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
  229. }
  230. /* ok... now we should have target_delay +- max_diff on the alsa side.
  231. *
  232. * calculate the number of frames, we want to get.
  233. */
  234. double resamp_rate = (double)jack_sample_rate / (double)sample_rate; // == nframes / alsa_samples.
  235. double request_samples = nframes / resamp_rate; //== alsa_samples;
  236. double offset = delay - target_delay;
  237. //double frlen = request_samples - offset / catch_factor;
  238. double frlen = request_samples - offset;
  239. double compute_factor = frlen / (double) nframes;
  240. double diff_value = pow(current_resample_factor - compute_factor, 3) / (double) catch_factor;
  241. current_resample_factor -= diff_value;
  242. rlen = ceil( ((double)nframes) * current_resample_factor ) + 2;
  243. if ( (print_counter--) == 0 ) {
  244. print_counter = 10;
  245. printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
  246. }
  247. /*
  248. * now this should do it...
  249. */
  250. outbuf = alloca( rlen * sizeof( ALSASAMPLE ) * num_channels );
  251. floatbuf = alloca( rlen * sizeof( float ) );
  252. resampbuf = alloca( nframes * sizeof( float ) );
  253. /*
  254. * render jack ports to the outbuf...
  255. */
  256. int chn = 0;
  257. JSList *node = playback_ports;
  258. JSList *src_node = playback_srcs;
  259. SRC_DATA src;
  260. while ( node != NULL) {
  261. int i;
  262. jack_port_t *port = (jack_port_t *) node->data;
  263. float *buf = jack_port_get_buffer (port, nframes);
  264. SRC_STATE *src_state = src_node->data;
  265. src.data_in = buf;
  266. src.input_frames = nframes;
  267. src.data_out = resampbuf;
  268. src.output_frames = rlen;
  269. src.end_of_input = 0;
  270. //src.src_ratio = (float) frlen / (float) nframes;
  271. src.src_ratio = current_resample_factor;
  272. //src_set_ratio( src_state, src.src_ratio );
  273. src_process( src_state, &src );
  274. for (i = 0; i < rlen; i++) {
  275. outbuf[chn+ i*num_channels] = resampbuf[i] * 32767;
  276. }
  277. src_node = jack_slist_next (src_node);
  278. node = jack_slist_next (node);
  279. chn++;
  280. }
  281. // now write the output...
  282. again:
  283. err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen);
  284. if ( err < 0 ) {
  285. //printf( "err = %d\n", err );
  286. if (xrun_recovery(alsa_handle, err) < 0) {
  287. //printf("Write error: %s\n", snd_strerror(err));
  288. //exit(EXIT_FAILURE);
  289. }
  290. goto again;
  291. }
  292. // if( err != rlen ) {
  293. // printf( "write = %d\n", rlen );
  294. // }
  295. return 0;
  296. }
  297. /**
  298. * Allocate the necessary jack ports...
  299. */
  300. void alloc_ports(int n_capture, int n_playback)
  301. {
  302. int port_flags = JackPortIsOutput;
  303. int chn;
  304. jack_port_t *port;
  305. char buf[32];
  306. capture_ports = NULL;
  307. for (chn = 0; chn < n_capture; chn++) {
  308. snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);
  309. port = jack_port_register (client, buf,
  310. JACK_DEFAULT_AUDIO_TYPE,
  311. port_flags, 0);
  312. if (!port) {
  313. printf( "jacknet_client: cannot register port for %s", buf);
  314. break;
  315. }
  316. capture_srcs = jack_slist_append( capture_srcs, src_new( SRC_SINC_FASTEST, 1, NULL ) );
  317. capture_ports = jack_slist_append (capture_ports, port);
  318. }
  319. port_flags = JackPortIsInput;
  320. playback_ports = NULL;
  321. for (chn = 0; chn < n_playback; chn++) {
  322. snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);
  323. port = jack_port_register (client, buf,
  324. JACK_DEFAULT_AUDIO_TYPE,
  325. port_flags, 0);
  326. if (!port) {
  327. printf( "jacknet_client: cannot register port for %s", buf);
  328. break;
  329. }
  330. playback_srcs = jack_slist_append( playback_srcs, src_new( SRC_SINC_FASTEST, 1, NULL ) );
  331. playback_ports = jack_slist_append (playback_ports, port);
  332. }
  333. }
  334. /**
  335. * This is the shutdown callback for this JACK application.
  336. * It is called by JACK if the server ever shuts down or
  337. * decides to disconnect the client.
  338. */
  339. void jack_shutdown (void *arg)
  340. {
  341. exit (1);
  342. }
  343. /**
  344. * be user friendly.
  345. * be user friendly.
  346. * be user friendly.
  347. */
  348. void printUsage()
  349. {
  350. fprintf(stderr, "usage: alsa_out [options]\n"
  351. "\n"
  352. " -j <jack name> - reports a different name to jack\n"
  353. " -d <alsa_device> \n"
  354. " -c <channels> \n"
  355. " -p <period_size> \n"
  356. " -n <num_period> \n"
  357. " -r <sample_rate> \n"
  358. " -m <max_diff> \n"
  359. " -t <target_delay> \n"
  360. " -f <catch_factor> \n"
  361. "\n");
  362. }
  363. /**
  364. * the main function....
  365. */
  366. int main (int argc, char *argv[])
  367. {
  368. char jack_name[30] = "alsa_out";
  369. char alsa_device[30] = "hw:0";
  370. extern char *optarg;
  371. extern int optind, optopt;
  372. int errflg = 0;
  373. int c;
  374. while ((c = getopt(argc, argv, ":j:r:c:p:n:d:m:t:f:")) != -1) {
  375. switch (c) {
  376. case 'j':
  377. strcpy(jack_name, optarg);
  378. break;
  379. case 'r':
  380. sample_rate = atoi(optarg);
  381. break;
  382. case 'c':
  383. num_channels = atoi(optarg);
  384. break;
  385. case 'p':
  386. period_size = atoi(optarg);
  387. break;
  388. case 'n':
  389. num_periods = atoi(optarg);
  390. break;
  391. case 'd':
  392. strcpy(alsa_device, optarg);
  393. break;
  394. case 't':
  395. target_delay = atoi(optarg);
  396. break;
  397. case 'm':
  398. max_diff = atoi(optarg);
  399. break;
  400. case 'f':
  401. catch_factor = atoi(optarg);
  402. break;
  403. case ':':
  404. fprintf(stderr,
  405. "Option -%c requires an operand\n", optopt);
  406. errflg++;
  407. break;
  408. case '?':
  409. fprintf(stderr,
  410. "Unrecognized option: -%c\n", optopt);
  411. errflg++;
  412. }
  413. }
  414. if (errflg) {
  415. printUsage();
  416. exit(2);
  417. }
  418. // Setup target delay and max_diff for the normal user, who does not play with them...
  419. if (!target_delay)
  420. target_delay = num_periods * period_size / 2;
  421. if (!max_diff)
  422. max_diff = period_size / 2;
  423. if ((client = jack_client_new(jack_name)) == 0) {
  424. fprintf (stderr, "jack server not running?\n");
  425. return 1;
  426. }
  427. /* tell the JACK server to call `process()' whenever
  428. there is work to be done.
  429. */
  430. jack_set_process_callback(client, process, 0);
  431. /* tell the JACK server to call `jack_shutdown()' if
  432. it ever shuts down, either entirely, or if it
  433. just decides to stop calling us.
  434. */
  435. jack_on_shutdown(client, jack_shutdown, 0);
  436. // alloc input ports, which are blasted out to alsa...
  437. alloc_ports( 0, num_channels );
  438. // get jack sample_rate
  439. jack_sample_rate = jack_get_sample_rate(client);
  440. if (!sample_rate)
  441. sample_rate = jack_sample_rate;
  442. current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
  443. // now open the alsa fd...
  444. alsa_handle = open_audiofd( alsa_device, 0, sample_rate, num_channels, period_size, num_periods);
  445. if (alsa_handle < 0)
  446. exit(20);
  447. /* tell the JACK server that we are ready to roll */
  448. if (jack_activate (client)) {
  449. fprintf (stderr, "cannot activate client");
  450. return 1;
  451. }
  452. while (1) sleep(1);
  453. jack_client_close (client);
  454. exit (0);
  455. }