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