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