1 /* 2 * This small demo sends a simple sinusoidal wave to your speakers. 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sched.h> 9 #include <errno.h> 10 #include <getopt.h> 11 #include "../include/asoundlib.h" 12 #include <sys/time.h> 13 #include <math.h> 14 15 static char *device = "plughw:0,0"; /* playback device */ 16 static snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */ 17 static unsigned int rate = 44100; /* stream rate */ 18 static unsigned int channels = 1; /* count of channels */ 19 static unsigned int buffer_time = 500000; /* ring buffer length in us */ 20 static unsigned int period_time = 100000; /* period time in us */ 21 static double freq = 440; /* sinusoidal wave frequency in Hz */ 22 static int verbose = 0; /* verbose flag */ 23 static int resample = 1; /* enable alsa-lib resampling */ 24 static int period_event = 0; /* produce poll event after each period */ 25 26 static snd_pcm_sframes_t buffer_size; 27 static snd_pcm_sframes_t period_size; 28 static snd_output_t *output = NULL; 29 30 static void generate_sine(const snd_pcm_channel_area_t *areas, 31 snd_pcm_uframes_t offset, 32 int count, double *_phase) 33 { 34 static double max_phase = 2. * M_PI; 35 double phase = *_phase; 36 double step = max_phase*freq/(double)rate; 37 double res; 38 unsigned char *samples[channels], *tmp; 39 int steps[channels]; 40 unsigned int chn, byte; 41 union { 42 int i; 43 unsigned char c[4]; 44 } ires; 45 unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1; 46 int bps = snd_pcm_format_width(format) / 8; /* bytes per sample */ 47 48 /* verify and prepare the contents of areas */ 49 for (chn = 0; chn < channels; chn++) { 50 if ((areas[chn].first % 8) != 0) { 51 printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first); 52 exit(EXIT_FAILURE); 53 } 54 samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8)); 55 if ((areas[chn].step % 16) != 0) { 56 printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step); 57 exit(EXIT_FAILURE); 58 } 59 steps[chn] = areas[chn].step / 8; 60 samples[chn] += offset * steps[chn]; 61 } 62 /* fill the channel areas */ 63 while (count-- > 0) { 64 res = sin(phase) * maxval; 65 ires.i = res; 66 tmp = ires.c; 67 for (chn = 0; chn < channels; chn++) { 68 for (byte = 0; byte < (unsigned int)bps; byte++) 69 *(samples[chn] + byte) = tmp[byte]; 70 samples[chn] += steps[chn]; 71 } 72 phase += step; 73 if (phase >= max_phase) 74 phase -= max_phase; 75 } 76 *_phase = phase; 77 } 78 79 static int set_hwparams(snd_pcm_t *handle, 80 snd_pcm_hw_params_t *params, 81 snd_pcm_access_t access) 82 { 83 unsigned int rrate; 84 snd_pcm_uframes_t size; 85 int err, dir; 86 87 /* choose all parameters */ 88 err = snd_pcm_hw_params_any(handle, params); 89 if (err < 0) { 90 printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); 91 return err; 92 } 93 /* set hardware resampling */ 94 err = snd_pcm_hw_params_set_rate_resample(handle, params, resample); 95 if (err < 0) { 96 printf("Resampling setup failed for playback: %s\n", snd_strerror(err)); 97 return err; 98 } 99 /* set the interleaved read/write format */ 100 err = snd_pcm_hw_params_set_access(handle, params, access); 101 if (err < 0) { 102 printf("Access type not available for playback: %s\n", snd_strerror(err)); 103 return err; 104 } 105 /* set the sample format */ 106 err = snd_pcm_hw_params_set_format(handle, params, format); 107 if (err < 0) { 108 printf("Sample format not available for playback: %s\n", snd_strerror(err)); 109 return err; 110 } 111 /* set the count of channels */ 112 err = snd_pcm_hw_params_set_channels(handle, params, channels); 113 if (err < 0) { 114 printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); 115 return err; 116 } 117 /* set the stream rate */ 118 rrate = rate; 119 err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); 120 if (err < 0) { 121 printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); 122 return err; 123 } 124 if (rrate != rate) { 125 printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); 126 return -EINVAL; 127 } 128 /* set the buffer time */ 129 err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); 130 if (err < 0) { 131 printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); 132 return err; 133 } 134 err = snd_pcm_hw_params_get_buffer_size(params, &size); 135 if (err < 0) { 136 printf("Unable to get buffer size for playback: %s\n", snd_strerror(err)); 137 return err; 138 } 139 buffer_size = size; 140 /* set the period time */ 141 err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); 142 if (err < 0) { 143 printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); 144 return err; 145 } 146 err = snd_pcm_hw_params_get_period_size(params, &size, &dir); 147 if (err < 0) { 148 printf("Unable to get period size for playback: %s\n", snd_strerror(err)); 149 return err; 150 } 151 period_size = size; 152 /* write the parameters to device */ 153 err = snd_pcm_hw_params(handle, params); 154 if (err < 0) { 155 printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); 156 return err; 157 } 158 return 0; 159 } 160 161 static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) 162 { 163 int err; 164 165 /* get the current swparams */ 166 err = snd_pcm_sw_params_current(handle, swparams); 167 if (err < 0) { 168 printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); 169 return err; 170 } 171 /* start the transfer when the buffer is almost full: */ 172 /* (buffer_size / avail_min) * avail_min */ 173 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); 174 if (err < 0) { 175 printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); 176 return err; 177 } 178 /* allow the transfer when at least period_size samples can be processed */ 179 /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ 180 err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size); 181 if (err < 0) { 182 printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); 183 return err; 184 } 185 /* enable period events when requested */ 186 if (period_event) { 187 err = snd_pcm_sw_params_set_period_event(handle, swparams, 1); 188 if (err < 0) { 189 printf("Unable to set period event: %s\n", snd_strerror(err)); 190 return err; 191 } 192 } 193 /* write the parameters to the playback device */ 194 err = snd_pcm_sw_params(handle, swparams); 195 if (err < 0) { 196 printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); 197 return err; 198 } 199 return 0; 200 } 201 202 /* 203 * Underrun and suspend recovery 204 */ 205 206 static int xrun_recovery(snd_pcm_t *handle, int err) 207 { 208 if (verbose) 209 printf("stream recovery\n"); 210 if (err == -EPIPE) { /* under-run */ 211 err = snd_pcm_prepare(handle); 212 if (err < 0) 213 printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); 214 return 0; 215 } else if (err == -ESTRPIPE) { 216 while ((err = snd_pcm_resume(handle)) == -EAGAIN) 217 sleep(1); /* wait until the suspend flag is released */ 218 if (err < 0) { 219 err = snd_pcm_prepare(handle); 220 if (err < 0) 221 printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); 222 } 223 return 0; 224 } 225 return err; 226 } 227 228 /* 229 * Transfer method - write only 230 */ 231 232 static int write_loop(snd_pcm_t *handle, 233 signed short *samples, 234 snd_pcm_channel_area_t *areas) 235 { 236 double phase = 0; 237 signed short *ptr; 238 int err, cptr; 239 240 while (1) { 241 generate_sine(areas, 0, period_size, &phase); 242 ptr = samples; 243 cptr = period_size; 244 while (cptr > 0) { 245 err = snd_pcm_writei(handle, ptr, cptr); 246 if (err == -EAGAIN) 247 continue; 248 if (err < 0) { 249 if (xrun_recovery(handle, err) < 0) { 250 printf("Write error: %s\n", snd_strerror(err)); 251 exit(EXIT_FAILURE); 252 } 253 break; /* skip one period */ 254 } 255 ptr += err * channels; 256 cptr -= err; 257 } 258 } 259 } 260 261 /* 262 * Transfer method - write and wait for room in buffer using poll 263 */ 264 265 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count) 266 { 267 unsigned short revents; 268 269 while (1) { 270 poll(ufds, count, -1); 271 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents); 272 if (revents & POLLERR) 273 return -EIO; 274 if (revents & POLLOUT) 275 return 0; 276 } 277 } 278 279 static int write_and_poll_loop(snd_pcm_t *handle, 280 signed short *samples, 281 snd_pcm_channel_area_t *areas) 282 { 283 struct pollfd *ufds; 284 double phase = 0; 285 signed short *ptr; 286 int err, count, cptr, init; 287 288 count = snd_pcm_poll_descriptors_count (handle); 289 if (count <= 0) { 290 printf("Invalid poll descriptors count\n"); 291 return count; 292 } 293 294 ufds = malloc(sizeof(struct pollfd) * count); 295 if (ufds == NULL) { 296 printf("No enough memory\n"); 297 return -ENOMEM; 298 } 299 if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) { 300 printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err)); 301 return err; 302 } 303 304 init = 1; 305 while (1) { 306 if (!init) { 307 err = wait_for_poll(handle, ufds, count); 308 if (err < 0) { 309 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN || 310 snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) { 311 err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; 312 if (xrun_recovery(handle, err) < 0) { 313 printf("Write error: %s\n", snd_strerror(err)); 314 exit(EXIT_FAILURE); 315 } 316 init = 1; 317 } else { 318 printf("Wait for poll failed\n"); 319 return err; 320 } 321 } 322 } 323 324 generate_sine(areas, 0, period_size, &phase); 325 ptr = samples; 326 cptr = period_size; 327 while (cptr > 0) { 328 err = snd_pcm_writei(handle, ptr, cptr); 329 if (err < 0) { 330 if (xrun_recovery(handle, err) < 0) { 331 printf("Write error: %s\n", snd_strerror(err)); 332 exit(EXIT_FAILURE); 333 } 334 init = 1; 335 break; /* skip one period */ 336 } 337 if (snd_pcm_state(handle) == SND_PCM_STATE_RUNNING) 338 init = 0; 339 ptr += err * channels; 340 cptr -= err; 341 if (cptr == 0) 342 break; 343 /* it is possible, that the initial buffer cannot store */ 344 /* all data from the last period, so wait awhile */ 345 err = wait_for_poll(handle, ufds, count); 346 if (err < 0) { 347 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN || 348 snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) { 349 err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; 350 if (xrun_recovery(handle, err) < 0) { 351 printf("Write error: %s\n", snd_strerror(err)); 352 exit(EXIT_FAILURE); 353 } 354 init = 1; 355 } else { 356 printf("Wait for poll failed\n"); 357 return err; 358 } 359 } 360 } 361 } 362 } 363 364 /* 365 * Transfer method - asynchronous notification 366 */ 367 368 struct async_private_data { 369 signed short *samples; 370 snd_pcm_channel_area_t *areas; 371 double phase; 372 }; 373 374 static void async_callback(snd_async_handler_t *ahandler) 375 { 376 snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); 377 struct async_private_data *data = snd_async_handler_get_callback_private(ahandler); 378 signed short *samples = data->samples; 379 snd_pcm_channel_area_t *areas = data->areas; 380 snd_pcm_sframes_t avail; 381 int err; 382 383 avail = snd_pcm_avail_update(handle); 384 while (avail >= period_size) { 385 generate_sine(areas, 0, period_size, &data->phase); 386 err = snd_pcm_writei(handle, samples, period_size); 387 if (err < 0) { 388 printf("Write error: %s\n", snd_strerror(err)); 389 exit(EXIT_FAILURE); 390 } 391 if (err != period_size) { 392 printf("Write error: written %i expected %li\n", err, period_size); 393 exit(EXIT_FAILURE); 394 } 395 avail = snd_pcm_avail_update(handle); 396 } 397 } 398 399 static int async_loop(snd_pcm_t *handle, 400 signed short *samples, 401 snd_pcm_channel_area_t *areas) 402 { 403 struct async_private_data data; 404 snd_async_handler_t *ahandler; 405 int err, count; 406 407 data.samples = samples; 408 data.areas = areas; 409 data.phase = 0; 410 err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, &data); 411 if (err < 0) { 412 printf("Unable to register async handler\n"); 413 exit(EXIT_FAILURE); 414 } 415 for (count = 0; count < 2; count++) { 416 generate_sine(areas, 0, period_size, &data.phase); 417 err = snd_pcm_writei(handle, samples, period_size); 418 if (err < 0) { 419 printf("Initial write error: %s\n", snd_strerror(err)); 420 exit(EXIT_FAILURE); 421 } 422 if (err != period_size) { 423 printf("Initial write error: written %i expected %li\n", err, period_size); 424 exit(EXIT_FAILURE); 425 } 426 } 427 if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) { 428 err = snd_pcm_start(handle); 429 if (err < 0) { 430 printf("Start error: %s\n", snd_strerror(err)); 431 exit(EXIT_FAILURE); 432 } 433 } 434 435 /* because all other work is done in the signal handler, 436 suspend the process */ 437 while (1) { 438 sleep(1); 439 } 440 } 441 442 /* 443 * Transfer method - asynchronous notification + direct write 444 */ 445 446 static void async_direct_callback(snd_async_handler_t *ahandler) 447 { 448 snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); 449 struct async_private_data *data = snd_async_handler_get_callback_private(ahandler); 450 const snd_pcm_channel_area_t *my_areas; 451 snd_pcm_uframes_t offset, frames, size; 452 snd_pcm_sframes_t avail, commitres; 453 snd_pcm_state_t state; 454 int first = 0, err; 455 456 while (1) { 457 state = snd_pcm_state(handle); 458 if (state == SND_PCM_STATE_XRUN) { 459 err = xrun_recovery(handle, -EPIPE); 460 if (err < 0) { 461 printf("XRUN recovery failed: %s\n", snd_strerror(err)); 462 exit(EXIT_FAILURE); 463 } 464 first = 1; 465 } else if (state == SND_PCM_STATE_SUSPENDED) { 466 err = xrun_recovery(handle, -ESTRPIPE); 467 if (err < 0) { 468 printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); 469 exit(EXIT_FAILURE); 470 } 471 } 472 avail = snd_pcm_avail_update(handle); 473 if (avail < 0) { 474 err = xrun_recovery(handle, avail); 475 if (err < 0) { 476 printf("avail update failed: %s\n", snd_strerror(err)); 477 exit(EXIT_FAILURE); 478 } 479 first = 1; 480 continue; 481 } 482 if (avail < period_size) { 483 if (first) { 484 first = 0; 485 err = snd_pcm_start(handle); 486 if (err < 0) { 487 printf("Start error: %s\n", snd_strerror(err)); 488 exit(EXIT_FAILURE); 489 } 490 } else { 491 break; 492 } 493 continue; 494 } 495 size = period_size; 496 while (size > 0) { 497 frames = size; 498 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); 499 if (err < 0) { 500 if ((err = xrun_recovery(handle, err)) < 0) { 501 printf("MMAP begin avail error: %s\n", snd_strerror(err)); 502 exit(EXIT_FAILURE); 503 } 504 first = 1; 505 } 506 generate_sine(my_areas, offset, frames, &data->phase); 507 commitres = snd_pcm_mmap_commit(handle, offset, frames); 508 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { 509 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { 510 printf("MMAP commit error: %s\n", snd_strerror(err)); 511 exit(EXIT_FAILURE); 512 } 513 first = 1; 514 } 515 size -= frames; 516 } 517 } 518 } 519 520 static int async_direct_loop(snd_pcm_t *handle, 521 signed short *samples ATTRIBUTE_UNUSED, 522 snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED) 523 { 524 struct async_private_data data; 525 snd_async_handler_t *ahandler; 526 const snd_pcm_channel_area_t *my_areas; 527 snd_pcm_uframes_t offset, frames, size; 528 snd_pcm_sframes_t commitres; 529 int err, count; 530 531 data.samples = NULL; /* we do not require the global sample area for direct write */ 532 data.areas = NULL; /* we do not require the global areas for direct write */ 533 data.phase = 0; 534 err = snd_async_add_pcm_handler(&ahandler, handle, async_direct_callback, &data); 535 if (err < 0) { 536 printf("Unable to register async handler\n"); 537 exit(EXIT_FAILURE); 538 } 539 for (count = 0; count < 2; count++) { 540 size = period_size; 541 while (size > 0) { 542 frames = size; 543 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); 544 if (err < 0) { 545 if ((err = xrun_recovery(handle, err)) < 0) { 546 printf("MMAP begin avail error: %s\n", snd_strerror(err)); 547 exit(EXIT_FAILURE); 548 } 549 } 550 generate_sine(my_areas, offset, frames, &data.phase); 551 commitres = snd_pcm_mmap_commit(handle, offset, frames); 552 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { 553 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { 554 printf("MMAP commit error: %s\n", snd_strerror(err)); 555 exit(EXIT_FAILURE); 556 } 557 } 558 size -= frames; 559 } 560 } 561 err = snd_pcm_start(handle); 562 if (err < 0) { 563 printf("Start error: %s\n", snd_strerror(err)); 564 exit(EXIT_FAILURE); 565 } 566 567 /* because all other work is done in the signal handler, 568 suspend the process */ 569 while (1) { 570 sleep(1); 571 } 572 } 573 574 /* 575 * Transfer method - direct write only 576 */ 577 578 static int direct_loop(snd_pcm_t *handle, 579 signed short *samples ATTRIBUTE_UNUSED, 580 snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED) 581 { 582 double phase = 0; 583 const snd_pcm_channel_area_t *my_areas; 584 snd_pcm_uframes_t offset, frames, size; 585 snd_pcm_sframes_t avail, commitres; 586 snd_pcm_state_t state; 587 int err, first = 1; 588 589 while (1) { 590 state = snd_pcm_state(handle); 591 if (state == SND_PCM_STATE_XRUN) { 592 err = xrun_recovery(handle, -EPIPE); 593 if (err < 0) { 594 printf("XRUN recovery failed: %s\n", snd_strerror(err)); 595 return err; 596 } 597 first = 1; 598 } else if (state == SND_PCM_STATE_SUSPENDED) { 599 err = xrun_recovery(handle, -ESTRPIPE); 600 if (err < 0) { 601 printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); 602 return err; 603 } 604 } 605 avail = snd_pcm_avail_update(handle); 606 if (avail < 0) { 607 err = xrun_recovery(handle, avail); 608 if (err < 0) { 609 printf("avail update failed: %s\n", snd_strerror(err)); 610 return err; 611 } 612 first = 1; 613 continue; 614 } 615 if (avail < period_size) { 616 if (first) { 617 first = 0; 618 err = snd_pcm_start(handle); 619 if (err < 0) { 620 printf("Start error: %s\n", snd_strerror(err)); 621 exit(EXIT_FAILURE); 622 } 623 } else { 624 err = snd_pcm_wait(handle, -1); 625 if (err < 0) { 626 if ((err = xrun_recovery(handle, err)) < 0) { 627 printf("snd_pcm_wait error: %s\n", snd_strerror(err)); 628 exit(EXIT_FAILURE); 629 } 630 first = 1; 631 } 632 } 633 continue; 634 } 635 size = period_size; 636 while (size > 0) { 637 frames = size; 638 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); 639 if (err < 0) { 640 if ((err = xrun_recovery(handle, err)) < 0) { 641 printf("MMAP begin avail error: %s\n", snd_strerror(err)); 642 exit(EXIT_FAILURE); 643 } 644 first = 1; 645 } 646 generate_sine(my_areas, offset, frames, &phase); 647 commitres = snd_pcm_mmap_commit(handle, offset, frames); 648 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { 649 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { 650 printf("MMAP commit error: %s\n", snd_strerror(err)); 651 exit(EXIT_FAILURE); 652 } 653 first = 1; 654 } 655 size -= frames; 656 } 657 } 658 } 659 660 /* 661 * Transfer method - direct write only using mmap_write functions 662 */ 663 664 static int direct_write_loop(snd_pcm_t *handle, 665 signed short *samples, 666 snd_pcm_channel_area_t *areas) 667 { 668 double phase = 0; 669 signed short *ptr; 670 int err, cptr; 671 672 while (1) { 673 generate_sine(areas, 0, period_size, &phase); 674 ptr = samples; 675 cptr = period_size; 676 while (cptr > 0) { 677 err = snd_pcm_mmap_writei(handle, ptr, cptr); 678 if (err == -EAGAIN) 679 continue; 680 if (err < 0) { 681 if (xrun_recovery(handle, err) < 0) { 682 printf("Write error: %s\n", snd_strerror(err)); 683 exit(EXIT_FAILURE); 684 } 685 break; /* skip one period */ 686 } 687 ptr += err * channels; 688 cptr -= err; 689 } 690 } 691 } 692 693 /* 694 * 695 */ 696 697 struct transfer_method { 698 const char *name; 699 snd_pcm_access_t access; 700 int (*transfer_loop)(snd_pcm_t *handle, 701 signed short *samples, 702 snd_pcm_channel_area_t *areas); 703 }; 704 705 static struct transfer_method transfer_methods[] = { 706 { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop }, 707 { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop }, 708 { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop }, 709 { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop }, 710 { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop }, 711 { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop }, 712 { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop }, 713 { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL } 714 }; 715 716 static void help(void) 717 { 718 int k; 719 printf( 720 "Usage: pcm [OPTION]... [FILE]...\n" 721 "-h,--help help\n" 722 "-D,--device playback device\n" 723 "-r,--rate stream rate in Hz\n" 724 "-c,--channels count of channels in stream\n" 725 "-f,--frequency sine wave frequency in Hz\n" 726 "-b,--buffer ring buffer size in us\n" 727 "-p,--period period size in us\n" 728 "-m,--method transfer method\n" 729 "-o,--format sample format\n" 730 "-v,--verbose show the PCM setup parameters\n" 731 "-n,--noresample do not resample\n" 732 "-e,--pevent enable poll event after each period\n" 733 "\n"); 734 printf("Recognized sample formats are:"); 735 for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) { 736 const char *s = snd_pcm_format_name(k); 737 if (s) 738 printf(" %s", s); 739 } 740 printf("\n"); 741 printf("Recognized transfer methods are:"); 742 for (k = 0; transfer_methods[k].name; k++) 743 printf(" %s", transfer_methods[k].name); 744 printf("\n"); 745 } 746 747 int main(int argc, char *argv[]) 748 { 749 struct option long_option[] = 750 { 751 {"help", 0, NULL, 'h'}, 752 {"device", 1, NULL, 'D'}, 753 {"rate", 1, NULL, 'r'}, 754 {"channels", 1, NULL, 'c'}, 755 {"frequency", 1, NULL, 'f'}, 756 {"buffer", 1, NULL, 'b'}, 757 {"period", 1, NULL, 'p'}, 758 {"method", 1, NULL, 'm'}, 759 {"format", 1, NULL, 'o'}, 760 {"verbose", 1, NULL, 'v'}, 761 {"noresample", 1, NULL, 'n'}, 762 {"pevent", 1, NULL, 'e'}, 763 {NULL, 0, NULL, 0}, 764 }; 765 snd_pcm_t *handle; 766 int err, morehelp; 767 snd_pcm_hw_params_t *hwparams; 768 snd_pcm_sw_params_t *swparams; 769 int method = 0; 770 signed short *samples; 771 unsigned int chn; 772 snd_pcm_channel_area_t *areas; 773 774 snd_pcm_hw_params_alloca(&hwparams); 775 snd_pcm_sw_params_alloca(&swparams); 776 777 morehelp = 0; 778 while (1) { 779 int c; 780 if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0) 781 break; 782 switch (c) { 783 case 'h': 784 morehelp++; 785 break; 786 case 'D': 787 device = strdup(optarg); 788 break; 789 case 'r': 790 rate = atoi(optarg); 791 rate = rate < 4000 ? 4000 : rate; 792 rate = rate > 196000 ? 196000 : rate; 793 break; 794 case 'c': 795 channels = atoi(optarg); 796 channels = channels < 1 ? 1 : channels; 797 channels = channels > 1024 ? 1024 : channels; 798 break; 799 case 'f': 800 freq = atoi(optarg); 801 freq = freq < 50 ? 50 : freq; 802 freq = freq > 5000 ? 5000 : freq; 803 break; 804 case 'b': 805 buffer_time = atoi(optarg); 806 buffer_time = buffer_time < 1000 ? 1000 : buffer_time; 807 buffer_time = buffer_time > 1000000 ? 1000000 : buffer_time; 808 break; 809 case 'p': 810 period_time = atoi(optarg); 811 period_time = period_time < 1000 ? 1000 : period_time; 812 period_time = period_time > 1000000 ? 1000000 : period_time; 813 break; 814 case 'm': 815 for (method = 0; transfer_methods[method].name; method++) 816 if (!strcasecmp(transfer_methods[method].name, optarg)) 817 break; 818 if (transfer_methods[method].name == NULL) 819 method = 0; 820 break; 821 case 'o': 822 for (format = 0; format < SND_PCM_FORMAT_LAST; format++) { 823 const char *format_name = snd_pcm_format_name(format); 824 if (format_name) 825 if (!strcasecmp(format_name, optarg)) 826 break; 827 } 828 if (format == SND_PCM_FORMAT_LAST) 829 format = SND_PCM_FORMAT_S16; 830 break; 831 case 'v': 832 verbose = 1; 833 break; 834 case 'n': 835 resample = 0; 836 break; 837 case 'e': 838 period_event = 1; 839 break; 840 } 841 } 842 843 if (morehelp) { 844 help(); 845 return 0; 846 } 847 848 err = snd_output_stdio_attach(&output, stdout, 0); 849 if (err < 0) { 850 printf("Output failed: %s\n", snd_strerror(err)); 851 return 0; 852 } 853 854 printf("Playback device is %s\n", device); 855 printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels); 856 printf("Sine wave rate is %.4fHz\n", freq); 857 printf("Using transfer method: %s\n", transfer_methods[method].name); 858 859 if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { 860 printf("Playback open error: %s\n", snd_strerror(err)); 861 return 0; 862 } 863 864 if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access)) < 0) { 865 printf("Setting of hwparams failed: %s\n", snd_strerror(err)); 866 exit(EXIT_FAILURE); 867 } 868 if ((err = set_swparams(handle, swparams)) < 0) { 869 printf("Setting of swparams failed: %s\n", snd_strerror(err)); 870 exit(EXIT_FAILURE); 871 } 872 873 if (verbose > 0) 874 snd_pcm_dump(handle, output); 875 876 samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8); 877 if (samples == NULL) { 878 printf("No enough memory\n"); 879 exit(EXIT_FAILURE); 880 } 881 882 areas = calloc(channels, sizeof(snd_pcm_channel_area_t)); 883 if (areas == NULL) { 884 printf("No enough memory\n"); 885 exit(EXIT_FAILURE); 886 } 887 for (chn = 0; chn < channels; chn++) { 888 areas[chn].addr = samples; 889 areas[chn].first = chn * snd_pcm_format_physical_width(format); 890 areas[chn].step = channels * snd_pcm_format_physical_width(format); 891 } 892 893 err = transfer_methods[method].transfer_loop(handle, samples, areas); 894 if (err < 0) 895 printf("Transfer failed: %s\n", snd_strerror(err)); 896 897 free(areas); 898 free(samples); 899 snd_pcm_close(handle); 900 return 0; 901 } 902 903