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.

650 lines
18KB

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