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.

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