00001
00002
00003
00004
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <sched.h>
00009 #include <errno.h>
00010 #include <getopt.h>
00011 #include "../include/asoundlib.h"
00012 #include <sys/time.h>
00013 #include <math.h>
00014
00015 static char *device = "plughw:0,0";
00016 static snd_pcm_format_t format = SND_PCM_FORMAT_S16;
00017 static unsigned int rate = 44100;
00018 static unsigned int channels = 1;
00019 static unsigned int buffer_time = 500000;
00020 static unsigned int period_time = 100000;
00021 static double freq = 440;
00022 static int verbose = 0;
00023 static int resample = 1;
00024 static int period_event = 0;
00025
00026 static snd_pcm_sframes_t buffer_size;
00027 static snd_pcm_sframes_t period_size;
00028 static snd_output_t *output = NULL;
00029
00030 static void generate_sine(const snd_pcm_channel_area_t *areas,
00031 snd_pcm_uframes_t offset,
00032 int count, double *_phase)
00033 {
00034 static double max_phase = 2. * M_PI;
00035 double phase = *_phase;
00036 double step = max_phase*freq/(double)rate;
00037 double res;
00038 unsigned char *samples[channels], *tmp;
00039 int steps[channels];
00040 unsigned int chn, byte;
00041 union {
00042 int i;
00043 unsigned char c[4];
00044 } ires;
00045 unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1;
00046 int bps = snd_pcm_format_width(format) / 8;
00047
00048
00049 for (chn = 0; chn < channels; chn++) {
00050 if ((areas[chn].first % 8) != 0) {
00051 printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first);
00052 exit(EXIT_FAILURE);
00053 }
00054 samples[chn] = (((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
00055 if ((areas[chn].step % 16) != 0) {
00056 printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step);
00057 exit(EXIT_FAILURE);
00058 }
00059 steps[chn] = areas[chn].step / 8;
00060 samples[chn] += offset * steps[chn];
00061 }
00062
00063 while (count-- > 0) {
00064 res = sin(phase) * maxval;
00065 ires.i = res;
00066 tmp = ires.c;
00067 for (chn = 0; chn < channels; chn++) {
00068 for (byte = 0; byte < (unsigned int)bps; byte++)
00069 *(samples[chn] + byte) = tmp[byte];
00070 samples[chn] += steps[chn];
00071 }
00072 phase += step;
00073 if (phase >= max_phase)
00074 phase -= max_phase;
00075 }
00076 *_phase = phase;
00077 }
00078
00079 static int set_hwparams(snd_pcm_t *handle,
00080 snd_pcm_hw_params_t *params,
00081 snd_pcm_access_t access)
00082 {
00083 unsigned int rrate;
00084 snd_pcm_uframes_t size;
00085 int err, dir;
00086
00087
00088 err = snd_pcm_hw_params_any(handle, params);
00089 if (err < 0) {
00090 printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
00091 return err;
00092 }
00093
00094 err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
00095 if (err < 0) {
00096 printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
00097 return err;
00098 }
00099
00100 err = snd_pcm_hw_params_set_access(handle, params, access);
00101 if (err < 0) {
00102 printf("Access type not available for playback: %s\n", snd_strerror(err));
00103 return err;
00104 }
00105
00106 err = snd_pcm_hw_params_set_format(handle, params, format);
00107 if (err < 0) {
00108 printf("Sample format not available for playback: %s\n", snd_strerror(err));
00109 return err;
00110 }
00111
00112 err = snd_pcm_hw_params_set_channels(handle, params, channels);
00113 if (err < 0) {
00114 printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
00115 return err;
00116 }
00117
00118 rrate = rate;
00119 err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
00120 if (err < 0) {
00121 printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
00122 return err;
00123 }
00124 if (rrate != rate) {
00125 printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
00126 return -EINVAL;
00127 }
00128
00129 err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
00130 if (err < 0) {
00131 printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
00132 return err;
00133 }
00134 err = snd_pcm_hw_params_get_buffer_size(params, &size);
00135 if (err < 0) {
00136 printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
00137 return err;
00138 }
00139 buffer_size = size;
00140
00141 err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
00142 if (err < 0) {
00143 printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
00144 return err;
00145 }
00146 err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
00147 if (err < 0) {
00148 printf("Unable to get period size for playback: %s\n", snd_strerror(err));
00149 return err;
00150 }
00151 period_size = size;
00152
00153 err = snd_pcm_hw_params(handle, params);
00154 if (err < 0) {
00155 printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
00156 return err;
00157 }
00158 return 0;
00159 }
00160
00161 static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
00162 {
00163 int err;
00164
00165
00166 err = snd_pcm_sw_params_current(handle, swparams);
00167 if (err < 0) {
00168 printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
00169 return err;
00170 }
00171
00172
00173 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);
00174 if (err < 0) {
00175 printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
00176 return err;
00177 }
00178
00179
00180 err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size);
00181 if (err < 0) {
00182 printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
00183 return err;
00184 }
00185
00186 if (period_event) {
00187 err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
00188 if (err < 0) {
00189 printf("Unable to set period event: %s\n", snd_strerror(err));
00190 return err;
00191 }
00192 }
00193
00194 err = snd_pcm_sw_params(handle, swparams);
00195 if (err < 0) {
00196 printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
00197 return err;
00198 }
00199 return 0;
00200 }
00201
00202
00203
00204
00205
00206 static int xrun_recovery(snd_pcm_t *handle, int err)
00207 {
00208 if (verbose)
00209 printf("stream recovery\n");
00210 if (err == -EPIPE) {
00211 err = snd_pcm_prepare(handle);
00212 if (err < 0)
00213 printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
00214 return 0;
00215 } else if (err == -ESTRPIPE) {
00216 while ((err = snd_pcm_resume(handle)) == -EAGAIN)
00217 sleep(1);
00218 if (err < 0) {
00219 err = snd_pcm_prepare(handle);
00220 if (err < 0)
00221 printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
00222 }
00223 return 0;
00224 }
00225 return err;
00226 }
00227
00228
00229
00230
00231
00232 static int write_loop(snd_pcm_t *handle,
00233 signed short *samples,
00234 snd_pcm_channel_area_t *areas)
00235 {
00236 double phase = 0;
00237 signed short *ptr;
00238 int err, cptr;
00239
00240 while (1) {
00241 generate_sine(areas, 0, period_size, &phase);
00242 ptr = samples;
00243 cptr = period_size;
00244 while (cptr > 0) {
00245 err = snd_pcm_writei(handle, ptr, cptr);
00246 if (err == -EAGAIN)
00247 continue;
00248 if (err < 0) {
00249 if (xrun_recovery(handle, err) < 0) {
00250 printf("Write error: %s\n", snd_strerror(err));
00251 exit(EXIT_FAILURE);
00252 }
00253 break;
00254 }
00255 ptr += err * channels;
00256 cptr -= err;
00257 }
00258 }
00259 }
00260
00261
00262
00263
00264
00265 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count)
00266 {
00267 unsigned short revents;
00268
00269 while (1) {
00270 poll(ufds, count, -1);
00271 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents);
00272 if (revents & POLLERR)
00273 return -EIO;
00274 if (revents & POLLOUT)
00275 return 0;
00276 }
00277 }
00278
00279 static int write_and_poll_loop(snd_pcm_t *handle,
00280 signed short *samples,
00281 snd_pcm_channel_area_t *areas)
00282 {
00283 struct pollfd *ufds;
00284 double phase = 0;
00285 signed short *ptr;
00286 int err, count, cptr, init;
00287
00288 count = snd_pcm_poll_descriptors_count (handle);
00289 if (count <= 0) {
00290 printf("Invalid poll descriptors count\n");
00291 return count;
00292 }
00293
00294 ufds = malloc(sizeof(struct pollfd) * count);
00295 if (ufds == NULL) {
00296 printf("No enough memory\n");
00297 return -ENOMEM;
00298 }
00299 if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) {
00300 printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err));
00301 return err;
00302 }
00303
00304 init = 1;
00305 while (1) {
00306 if (!init) {
00307 err = wait_for_poll(handle, ufds, count);
00308 if (err < 0) {
00309 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN ||
00310 snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) {
00311 err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
00312 if (xrun_recovery(handle, err) < 0) {
00313 printf("Write error: %s\n", snd_strerror(err));
00314 exit(EXIT_FAILURE);
00315 }
00316 init = 1;
00317 } else {
00318 printf("Wait for poll failed\n");
00319 return err;
00320 }
00321 }
00322 }
00323
00324 generate_sine(areas, 0, period_size, &phase);
00325 ptr = samples;
00326 cptr = period_size;
00327 while (cptr > 0) {
00328 err = snd_pcm_writei(handle, ptr, cptr);
00329 if (err < 0) {
00330 if (xrun_recovery(handle, err) < 0) {
00331 printf("Write error: %s\n", snd_strerror(err));
00332 exit(EXIT_FAILURE);
00333 }
00334 init = 1;
00335 break;
00336 }
00337 if (snd_pcm_state(handle) == SND_PCM_STATE_RUNNING)
00338 init = 0;
00339 ptr += err * channels;
00340 cptr -= err;
00341 if (cptr == 0)
00342 break;
00343
00344
00345 err = wait_for_poll(handle, ufds, count);
00346 if (err < 0) {
00347 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN ||
00348 snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) {
00349 err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
00350 if (xrun_recovery(handle, err) < 0) {
00351 printf("Write error: %s\n", snd_strerror(err));
00352 exit(EXIT_FAILURE);
00353 }
00354 init = 1;
00355 } else {
00356 printf("Wait for poll failed\n");
00357 return err;
00358 }
00359 }
00360 }
00361 }
00362 }
00363
00364
00365
00366
00367
00368 struct async_private_data {
00369 signed short *samples;
00370 snd_pcm_channel_area_t *areas;
00371 double phase;
00372 };
00373
00374 static void async_callback(snd_async_handler_t *ahandler)
00375 {
00376 snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
00377 struct async_private_data *data = snd_async_handler_get_callback_private(ahandler);
00378 signed short *samples = data->samples;
00379 snd_pcm_channel_area_t *areas = data->areas;
00380 snd_pcm_sframes_t avail;
00381 int err;
00382
00383 avail = snd_pcm_avail_update(handle);
00384 while (avail >= period_size) {
00385 generate_sine(areas, 0, period_size, &data->phase);
00386 err = snd_pcm_writei(handle, samples, period_size);
00387 if (err < 0) {
00388 printf("Initial write error: %s\n", snd_strerror(err));
00389 exit(EXIT_FAILURE);
00390 }
00391 if (err != period_size) {
00392 printf("Initial write error: written %i expected %li\n", err, period_size);
00393 exit(EXIT_FAILURE);
00394 }
00395 avail = snd_pcm_avail_update(handle);
00396 }
00397 }
00398
00399 static int async_loop(snd_pcm_t *handle,
00400 signed short *samples,
00401 snd_pcm_channel_area_t *areas)
00402 {
00403 struct async_private_data data;
00404 snd_async_handler_t *ahandler;
00405 int err, count;
00406
00407 data.samples = samples;
00408 data.areas = areas;
00409 data.phase = 0;
00410 err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, &data);
00411 if (err < 0) {
00412 printf("Unable to register async handler\n");
00413 exit(EXIT_FAILURE);
00414 }
00415 for (count = 0; count < 2; count++) {
00416 generate_sine(areas, 0, period_size, &data.phase);
00417 err = snd_pcm_writei(handle, samples, period_size);
00418 if (err < 0) {
00419 printf("Initial write error: %s\n", snd_strerror(err));
00420 exit(EXIT_FAILURE);
00421 }
00422 if (err != period_size) {
00423 printf("Initial write error: written %i expected %li\n", err, period_size);
00424 exit(EXIT_FAILURE);
00425 }
00426 }
00427 err = snd_pcm_start(handle);
00428 if (err < 0) {
00429 printf("Start error: %s\n", snd_strerror(err));
00430 exit(EXIT_FAILURE);
00431 }
00432
00433
00434
00435 while (1) {
00436 sleep(1);
00437 }
00438 }
00439
00440
00441
00442
00443
00444 static void async_direct_callback(snd_async_handler_t *ahandler)
00445 {
00446 snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
00447 struct async_private_data *data = snd_async_handler_get_callback_private(ahandler);
00448 const snd_pcm_channel_area_t *my_areas;
00449 snd_pcm_uframes_t offset, frames, size;
00450 snd_pcm_sframes_t avail, commitres;
00451 snd_pcm_state_t state;
00452 int first = 0, err;
00453
00454 while (1) {
00455 state = snd_pcm_state(handle);
00456 if (state == SND_PCM_STATE_XRUN) {
00457 err = xrun_recovery(handle, -EPIPE);
00458 if (err < 0) {
00459 printf("XRUN recovery failed: %s\n", snd_strerror(err));
00460 exit(EXIT_FAILURE);
00461 }
00462 first = 1;
00463 } else if (state == SND_PCM_STATE_SUSPENDED) {
00464 err = xrun_recovery(handle, -ESTRPIPE);
00465 if (err < 0) {
00466 printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
00467 exit(EXIT_FAILURE);
00468 }
00469 }
00470 avail = snd_pcm_avail_update(handle);
00471 if (avail < 0) {
00472 err = xrun_recovery(handle, avail);
00473 if (err < 0) {
00474 printf("avail update failed: %s\n", snd_strerror(err));
00475 exit(EXIT_FAILURE);
00476 }
00477 first = 1;
00478 continue;
00479 }
00480 if (avail < period_size) {
00481 if (first) {
00482 first = 0;
00483 err = snd_pcm_start(handle);
00484 if (err < 0) {
00485 printf("Start error: %s\n", snd_strerror(err));
00486 exit(EXIT_FAILURE);
00487 }
00488 } else {
00489 break;
00490 }
00491 continue;
00492 }
00493 size = period_size;
00494 while (size > 0) {
00495 frames = size;
00496 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
00497 if (err < 0) {
00498 if ((err = xrun_recovery(handle, err)) < 0) {
00499 printf("MMAP begin avail error: %s\n", snd_strerror(err));
00500 exit(EXIT_FAILURE);
00501 }
00502 first = 1;
00503 }
00504 generate_sine(my_areas, offset, frames, &data->phase);
00505 commitres = snd_pcm_mmap_commit(handle, offset, frames);
00506 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
00507 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
00508 printf("MMAP commit error: %s\n", snd_strerror(err));
00509 exit(EXIT_FAILURE);
00510 }
00511 first = 1;
00512 }
00513 size -= frames;
00514 }
00515 }
00516 }
00517
00518 static int async_direct_loop(snd_pcm_t *handle,
00519 signed short *samples ATTRIBUTE_UNUSED,
00520 snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED)
00521 {
00522 struct async_private_data data;
00523 snd_async_handler_t *ahandler;
00524 const snd_pcm_channel_area_t *my_areas;
00525 snd_pcm_uframes_t offset, frames, size;
00526 snd_pcm_sframes_t commitres;
00527 int err, count;
00528
00529 data.samples = NULL;
00530 data.areas = NULL;
00531 data.phase = 0;
00532 err = snd_async_add_pcm_handler(&ahandler, handle, async_direct_callback, &data);
00533 if (err < 0) {
00534 printf("Unable to register async handler\n");
00535 exit(EXIT_FAILURE);
00536 }
00537 for (count = 0; count < 2; count++) {
00538 size = period_size;
00539 while (size > 0) {
00540 frames = size;
00541 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
00542 if (err < 0) {
00543 if ((err = xrun_recovery(handle, err)) < 0) {
00544 printf("MMAP begin avail error: %s\n", snd_strerror(err));
00545 exit(EXIT_FAILURE);
00546 }
00547 }
00548 generate_sine(my_areas, offset, frames, &data.phase);
00549 commitres = snd_pcm_mmap_commit(handle, offset, frames);
00550 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
00551 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
00552 printf("MMAP commit error: %s\n", snd_strerror(err));
00553 exit(EXIT_FAILURE);
00554 }
00555 }
00556 size -= frames;
00557 }
00558 }
00559 err = snd_pcm_start(handle);
00560 if (err < 0) {
00561 printf("Start error: %s\n", snd_strerror(err));
00562 exit(EXIT_FAILURE);
00563 }
00564
00565
00566
00567 while (1) {
00568 sleep(1);
00569 }
00570 }
00571
00572
00573
00574
00575
00576 static int direct_loop(snd_pcm_t *handle,
00577 signed short *samples ATTRIBUTE_UNUSED,
00578 snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED)
00579 {
00580 double phase = 0;
00581 const snd_pcm_channel_area_t *my_areas;
00582 snd_pcm_uframes_t offset, frames, size;
00583 snd_pcm_sframes_t avail, commitres;
00584 snd_pcm_state_t state;
00585 int err, first = 1;
00586
00587 while (1) {
00588 state = snd_pcm_state(handle);
00589 if (state == SND_PCM_STATE_XRUN) {
00590 err = xrun_recovery(handle, -EPIPE);
00591 if (err < 0) {
00592 printf("XRUN recovery failed: %s\n", snd_strerror(err));
00593 return err;
00594 }
00595 first = 1;
00596 } else if (state == SND_PCM_STATE_SUSPENDED) {
00597 err = xrun_recovery(handle, -ESTRPIPE);
00598 if (err < 0) {
00599 printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
00600 return err;
00601 }
00602 }
00603 avail = snd_pcm_avail_update(handle);
00604 if (avail < 0) {
00605 err = xrun_recovery(handle, avail);
00606 if (err < 0) {
00607 printf("avail update failed: %s\n", snd_strerror(err));
00608 return err;
00609 }
00610 first = 1;
00611 continue;
00612 }
00613 if (avail < period_size) {
00614 if (first) {
00615 first = 0;
00616 err = snd_pcm_start(handle);
00617 if (err < 0) {
00618 printf("Start error: %s\n", snd_strerror(err));
00619 exit(EXIT_FAILURE);
00620 }
00621 } else {
00622 err = snd_pcm_wait(handle, -1);
00623 if (err < 0) {
00624 if ((err = xrun_recovery(handle, err)) < 0) {
00625 printf("snd_pcm_wait error: %s\n", snd_strerror(err));
00626 exit(EXIT_FAILURE);
00627 }
00628 first = 1;
00629 }
00630 }
00631 continue;
00632 }
00633 size = period_size;
00634 while (size > 0) {
00635 frames = size;
00636 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
00637 if (err < 0) {
00638 if ((err = xrun_recovery(handle, err)) < 0) {
00639 printf("MMAP begin avail error: %s\n", snd_strerror(err));
00640 exit(EXIT_FAILURE);
00641 }
00642 first = 1;
00643 }
00644 generate_sine(my_areas, offset, frames, &phase);
00645 commitres = snd_pcm_mmap_commit(handle, offset, frames);
00646 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
00647 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
00648 printf("MMAP commit error: %s\n", snd_strerror(err));
00649 exit(EXIT_FAILURE);
00650 }
00651 first = 1;
00652 }
00653 size -= frames;
00654 }
00655 }
00656 }
00657
00658
00659
00660
00661
00662 static int direct_write_loop(snd_pcm_t *handle,
00663 signed short *samples,
00664 snd_pcm_channel_area_t *areas)
00665 {
00666 double phase = 0;
00667 signed short *ptr;
00668 int err, cptr;
00669
00670 while (1) {
00671 generate_sine(areas, 0, period_size, &phase);
00672 ptr = samples;
00673 cptr = period_size;
00674 while (cptr > 0) {
00675 err = snd_pcm_mmap_writei(handle, ptr, cptr);
00676 if (err == -EAGAIN)
00677 continue;
00678 if (err < 0) {
00679 if (xrun_recovery(handle, err) < 0) {
00680 printf("Write error: %s\n", snd_strerror(err));
00681 exit(EXIT_FAILURE);
00682 }
00683 break;
00684 }
00685 ptr += err * channels;
00686 cptr -= err;
00687 }
00688 }
00689 }
00690
00691
00692
00693
00694
00695 struct transfer_method {
00696 const char *name;
00697 snd_pcm_access_t access;
00698 int (*transfer_loop)(snd_pcm_t *handle,
00699 signed short *samples,
00700 snd_pcm_channel_area_t *areas);
00701 };
00702
00703 static struct transfer_method transfer_methods[] = {
00704 { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop },
00705 { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop },
00706 { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop },
00707 { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop },
00708 { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop },
00709 { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop },
00710 { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop },
00711 { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL }
00712 };
00713
00714 static void help(void)
00715 {
00716 int k;
00717 printf(
00718 "Usage: pcm [OPTION]... [FILE]...\n"
00719 "-h,--help help\n"
00720 "-D,--device playback device\n"
00721 "-r,--rate stream rate in Hz\n"
00722 "-c,--channels count of channels in stream\n"
00723 "-f,--frequency sine wave frequency in Hz\n"
00724 "-b,--buffer ring buffer size in us\n"
00725 "-p,--period period size in us\n"
00726 "-m,--method transfer method\n"
00727 "-o,--format sample format\n"
00728 "-v,--verbose show the PCM setup parameters\n"
00729 "-n,--noresample do not resample\n"
00730 "-e,--pevent enable poll event after each period\n"
00731 "\n");
00732 printf("Recognized sample formats are:");
00733 for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
00734 const char *s = snd_pcm_format_name(k);
00735 if (s)
00736 printf(" %s", s);
00737 }
00738 printf("\n");
00739 printf("Recognized transfer methods are:");
00740 for (k = 0; transfer_methods[k].name; k++)
00741 printf(" %s", transfer_methods[k].name);
00742 printf("\n");
00743 }
00744
00745 int main(int argc, char *argv[])
00746 {
00747 struct option long_option[] =
00748 {
00749 {"help", 0, NULL, 'h'},
00750 {"device", 1, NULL, 'D'},
00751 {"rate", 1, NULL, 'r'},
00752 {"channels", 1, NULL, 'c'},
00753 {"frequency", 1, NULL, 'f'},
00754 {"buffer", 1, NULL, 'b'},
00755 {"period", 1, NULL, 'p'},
00756 {"method", 1, NULL, 'm'},
00757 {"format", 1, NULL, 'o'},
00758 {"verbose", 1, NULL, 'v'},
00759 {"noresample", 1, NULL, 'n'},
00760 {"pevent", 1, NULL, 'e'},
00761 {NULL, 0, NULL, 0},
00762 };
00763 snd_pcm_t *handle;
00764 int err, morehelp;
00765 snd_pcm_hw_params_t *hwparams;
00766 snd_pcm_sw_params_t *swparams;
00767 int method = 0;
00768 signed short *samples;
00769 unsigned int chn;
00770 snd_pcm_channel_area_t *areas;
00771
00772 snd_pcm_hw_params_alloca(&hwparams);
00773 snd_pcm_sw_params_alloca(&swparams);
00774
00775 morehelp = 0;
00776 while (1) {
00777 int c;
00778 if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0)
00779 break;
00780 switch (c) {
00781 case 'h':
00782 morehelp++;
00783 break;
00784 case 'D':
00785 device = strdup(optarg);
00786 break;
00787 case 'r':
00788 rate = atoi(optarg);
00789 rate = rate < 4000 ? 4000 : rate;
00790 rate = rate > 196000 ? 196000 : rate;
00791 break;
00792 case 'c':
00793 channels = atoi(optarg);
00794 channels = channels < 1 ? 1 : channels;
00795 channels = channels > 1024 ? 1024 : channels;
00796 break;
00797 case 'f':
00798 freq = atoi(optarg);
00799 freq = freq < 50 ? 50 : freq;
00800 freq = freq > 5000 ? 5000 : freq;
00801 break;
00802 case 'b':
00803 buffer_time = atoi(optarg);
00804 buffer_time = buffer_time < 1000 ? 1000 : buffer_time;
00805 buffer_time = buffer_time > 1000000 ? 1000000 : buffer_time;
00806 break;
00807 case 'p':
00808 period_time = atoi(optarg);
00809 period_time = period_time < 1000 ? 1000 : period_time;
00810 period_time = period_time > 1000000 ? 1000000 : period_time;
00811 break;
00812 case 'm':
00813 for (method = 0; transfer_methods[method].name; method++)
00814 if (!strcasecmp(transfer_methods[method].name, optarg))
00815 break;
00816 if (transfer_methods[method].name == NULL)
00817 method = 0;
00818 break;
00819 case 'o':
00820 for (format = 0; format < SND_PCM_FORMAT_LAST; format++) {
00821 const char *format_name = snd_pcm_format_name(format);
00822 if (format_name)
00823 if (!strcasecmp(format_name, optarg))
00824 break;
00825 }
00826 if (format == SND_PCM_FORMAT_LAST)
00827 format = SND_PCM_FORMAT_S16;
00828 break;
00829 case 'v':
00830 verbose = 1;
00831 break;
00832 case 'n':
00833 resample = 0;
00834 break;
00835 case 'e':
00836 period_event = 1;
00837 break;
00838 }
00839 }
00840
00841 if (morehelp) {
00842 help();
00843 return 0;
00844 }
00845
00846 err = snd_output_stdio_attach(&output, stdout, 0);
00847 if (err < 0) {
00848 printf("Output failed: %s\n", snd_strerror(err));
00849 return 0;
00850 }
00851
00852 printf("Playback device is %s\n", device);
00853 printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
00854 printf("Sine wave rate is %.4fHz\n", freq);
00855 printf("Using transfer method: %s\n", transfer_methods[method].name);
00856
00857 if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
00858 printf("Playback open error: %s\n", snd_strerror(err));
00859 return 0;
00860 }
00861
00862 if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access)) < 0) {
00863 printf("Setting of hwparams failed: %s\n", snd_strerror(err));
00864 exit(EXIT_FAILURE);
00865 }
00866 if ((err = set_swparams(handle, swparams)) < 0) {
00867 printf("Setting of swparams failed: %s\n", snd_strerror(err));
00868 exit(EXIT_FAILURE);
00869 }
00870
00871 if (verbose > 0)
00872 snd_pcm_dump(handle, output);
00873
00874 samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8);
00875 if (samples == NULL) {
00876 printf("No enough memory\n");
00877 exit(EXIT_FAILURE);
00878 }
00879
00880 areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
00881 if (areas == NULL) {
00882 printf("No enough memory\n");
00883 exit(EXIT_FAILURE);
00884 }
00885 for (chn = 0; chn < channels; chn++) {
00886 areas[chn].addr = samples;
00887 areas[chn].first = chn * snd_pcm_format_physical_width(format);
00888 areas[chn].step = channels * snd_pcm_format_physical_width(format);
00889 }
00890
00891 err = transfer_methods[method].transfer_loop(handle, samples, areas);
00892 if (err < 0)
00893 printf("Transfer failed: %s\n", snd_strerror(err));
00894
00895 free(areas);
00896 free(samples);
00897 snd_pcm_close(handle);
00898 return 0;
00899 }
00900