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