/* pcm.c * This small demo sends a simple sinusoidal wave to your speakers. */ #include #include #include #include #include #include #include "asoundlib.h" #include #include static char *device = "plughw:0,0"; /* playback device */ static SND_PCM_FORMAT_S16; /* sample format */ static unsigned int rate = 44100; /* stream rate */ static unsigned int channels = 1; /* count of channels */ static unsigned int buffer_time = 500000; /* ring buffer length in us */ static unsigned int period_time = 100000; /* period time in us */ static double freq = 440; /* sinusoidal wave frequency in Hz */ static int verbose = 0; /* verbose flag */ static int resample = 1; /* enable alsa-lib resampling */ static int period_event = 0; /* produce poll event after each period */ static snd_pcm_sframes_t buffer_size; static snd_pcm_sframes_t period_size; static snd_output_t *output = NULL; static void generate_sine(const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, int count, double *_phase) { static double max_phase = 2. * M_PI; double phase = *_phase; double step = max_phase*freq/(double)rate; double res; unsigned char *samples[channels], *tmp; int steps[channels]; unsigned int chn, byte; union {int i; unsigned char c[4];} ires; unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1; int bps = snd_pcm_format_width(format) / 8; /* bytes per sample */ /* verify and prepare the contents of areas */ for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8)); if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step); exit(EXIT_FAILURE); } steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; } /* fill the channel areas */ while (count-- > 0) { res = sin(phase) * maxval; ires.i = res; 6666 tmp = ires.c; 6767 for (chn = 0; chn < channels; chn++) { 6868 for (byte = 0; byte < (unsigned int)bps; byte++) 6969 *(samples[chn] + byte) = tmp[byte]; 7070 samples[chn] += steps[chn]; 7171 } 7272 phase += step; 7373 if (phase >= max_phase) 7474 phase -= max_phase; 7575 } 7676 *_phase = phase; 7777 } 7878 7979 static int set_hwparams("a9">snd_pcm_t *handle, 8080 "a10">snd_pcm_hw_params_t *params, 8181 "a11">snd_pcm_access_t access) 8282 { 8383 unsigned int rrate; 8484 snd_pcm_uframes_t size; 8585 int err, dir; 8686 8787 /* choose all parameters */ 8888 err = "a12">snd_pcm_hw_params_any(handle, params); 8989 if (err < 0) { 9090 printf("Broken configuration for playback: no configurations available: %s\n", "a13">snd_strerror(err)); 9191 return err; 9292 } 9393 /* set hardware resampling */ 9494 err = "a14">snd_pcm_hw_params_set_rate_resample(handle, params, resample); 9595 if (err < 0) { 9696 printf("Resampling setup failed for playback: %s\n", snd_strerror(err)); 9797 return err; 9898 } 9999 /* set the interleaved read/write format */ 100100 err = "a15">snd_pcm_hw_params_set_access(handle, params, access); 101101 if (err < 0) { 102102 printf("Access type not available for playback: %s\n", snd_strerror(err)); 103103 return err; 104104 } 105105 /* set the sample format */ 106106 err = "a16">snd_pcm_hw_params_set_format(handle, params, format); 107107 if (err < 0) { 108108 printf("Sample format not available for playback: %s\n", snd_strerror(err)); 109109 return err; 110110 } 111111 /* set the count of channels */ 112112 err = "a17">snd_pcm_hw_params_set_channels(handle, params, channels); 113113 if (err < 0) { 114114 printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); 115115 return err; 116116 } 117117 /* set the stream rate */ 118118 rrate = rate; 119119 err = "a18">snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); 120120 if (err < 0) { 121121 printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); 122122 return err; 123123 } 124124 if (rrate != rate) { 125125 printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); 126126 return -EINVAL; 127127 } 128128 /* set the buffer time */ 129129 err = "a19">snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); 130130 if (err < 0) { 131131 printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); 132132 return err; 133133 } 134134 err = "a20">snd_pcm_hw_params_get_buffer_size(params, &size); 135135 if (err < 0) { 136136 printf("Unable to get buffer size for playback: %s\n", snd_strerror(err)); 137137 return err; 138138 } 139139 buffer_size = size; 140140 /* set the period time */ 141141 err = "a21">snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); 142142 if (err < 0) { 143143 printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); 144144 return err; 145145 } 146146 err = "a22">snd_pcm_hw_params_get_period_size(params, &size, &dir); 147147 if (err < 0) { 148148 printf("Unable to get period size for playback: %s\n", snd_strerror(err)); 149149 return err; 150150 } 151151 period_size = size; 152152 /* write the parameters to device */ 153153 err = "a23">snd_pcm_hw_params(handle, params); 154154 if (err < 0) { 155155 printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); 156156 return err; 157157 } 158158 return 0; 159159 } 160160 161161 static int set_swparams(snd_pcm_t *handle, "a24">snd_pcm_sw_params_t *swparams) 162162 { 163163 int err; 164164 165165 /* get the current swparams */ 166166 err = "a25">snd_pcm_sw_params_current(handle, swparams); 167167 if (err < 0) { 168168 printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); 169169 return err; 170170 } 171171 /* start the transfer when the buffer is almost full: */ 172172 /* (buffer_size / avail_min) * avail_min */ 173173 err = "a26">snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); 174174 if (err < 0) { 175175 printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); 176176 return err; 177177 } 178178 /* allow the transfer when at least period_size samples can be processed */ 179179 /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ 180180 err = "a27">snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size); 181181 if (err < 0) { 182182 printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); 183183 return err; 184184 } 185185 /* enable period events when requested */ 186186 if (period_event) { 187187 err = "a28">snd_pcm_sw_params_set_period_event(handle, swparams, 1); 188188 if (err < 0) { 189189 printf("Unable to set period event: %s\n", snd_strerror(err)); 190190 return err; 191191 } 192192 } 193193 /* write the parameters to the playback device */ 194194 err = "a29">snd_pcm_sw_params(handle, swparams); 195195 if (err < 0) { 196196 printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); 197197 return err; 198198 } 199199 return 0; 200200 } 201201 202202 /* 203203 * Underrun and suspend recovery 204204 */ 205205 206206 static int xrun_recovery(snd_pcm_t *handle, int err) 207207 { 208208 if (verbose) 209209 printf("stream recovery\n"); 210210 if (err == -EPIPE) { /* under-run */ 211211 err = "a30">snd_pcm_prepare(handle); 212212 if (err < 0) 213213 printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); 214214 return 0; 215215 } else if (err == -ESTRPIPE) { 216216 while ((err = "a31">snd_pcm_resume(handle)) == -EAGAIN) 217217 sleep(1); /* wait until the suspend flag is released */ 218218 if (err < 0) { 219219 err = snd_pcm_prepare(handle); 220220 if (err < 0) 221221 printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); 222222 } 223223 return 0; 224224 } 225225 return err; 226226 } 227227 228228 /* 229229 * Transfer method - write only 230230 */ 231231 232232 static int write_loop(snd_pcm_t *handle, 233233 signed short *samples, 234234 snd_pcm_channel_area_t *areas) 235235 { 236236 double phase = 0; 237237 signed short *ptr; 238238 int err, cptr; 239239 240240 while (1) { 241241 generate_sine(areas, 0, period_size, &phase); 242242 ptr = samples; 243243 cptr = period_size; 244244 while (cptr > 0) { 245245 err = "a32">snd_pcm_writei(handle, ptr, cptr); 246246 if (err == -EAGAIN) 247247 continue; 248248 if (err < 0) { 249249 if (xrun_recovery(handle, err) < 0) { 250250 printf("Write error: %s\n", snd_strerror(err)); 251251 exit(EXIT_FAILURE); 252252 } 253253 break; /* skip one period */ 254254 } 255255 ptr += err * channels; 256256 cptr -= err; 257257 } 258258 } 259259 } 260260 261261 /* 262262 * Transfer method - write and wait for room in buffer using poll 263263 */ 264264 265265 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count) 266266 { 267267 unsigned short revents; 268268 269269 while (1) { 270270 poll(ufds, count, -1); 271271 "a33">snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents); 272272 if (revents & POLLERR) 273273 return -EIO; 274274 if (revents & POLLOUT) 275275 return 0; 276276 } 277277 } 278278 279279 static int write_and_poll_loop(snd_pcm_t *handle, 280280 signed short *samples, 281281 snd_pcm_channel_area_t *areas) 282282 { 283283 struct pollfd *ufds; 284284 double phase = 0; 285285 signed short *ptr; 286286 int err, count, cptr, init; 287287 288288 count = "a34">snd_pcm_poll_descriptors_count (handle); 289289 if (count <= 0) { 290290 printf("Invalid poll descriptors count\n"); 291291 return count; 292292 } 293293 294294 ufds = malloc(sizeof(struct pollfd) * count); 295295 if (ufds == NULL) { 296296 printf("No enough memory\n"); 297297 return -ENOMEM; 298298 } 299299 if ((err = "a35">snd_pcm_poll_descriptors(handle, ufds, count)) < 0) { 300300 printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err)); 301301 return err; 302302 } 303303 304304 init = 1; 305305 while (1) { 306306 if (!init) { 307307 err = wait_for_poll(handle, ufds, count); 308308 if (err < 0) { 309309 if ("a36">snd_pcm_state(handle) == "a37">SND_PCM_STATE_XRUN || 310310 snd_pcm_state(handle) == "a38">SND_PCM_STATE_SUSPENDED) { 311311 err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; 312312 if (xrun_recovery(handle, err) < 0) { 313313 printf("Write error: %s\n", snd_strerror(err)); 314314 exit(EXIT_FAILURE); 315315 } 316316 init = 1; 317317 } else { 318318 printf("Wait for poll failed\n"); 319319 return err; 320320 } 321321 } 322322 } 323323 324324 generate_sine(areas, 0, period_size, &phase); 325325 ptr = samples; 326326 cptr = period_size; 327327 while (cptr > 0) { 328328 err = snd_pcm_writei(handle, ptr, cptr); 329329 if (err < 0) { 330330 if (xrun_recovery(handle, err) < 0) { 331331 printf("Write error: %s\n", snd_strerror(err)); 332332 exit(EXIT_FAILURE); 333333 } 334334 init = 1; 335335 break; /* skip one period */ 336336 } 337337 if (snd_pcm_state(handle) == "a39">SND_PCM_STATE_RUNNING) 338338 init = 0; 339339 ptr += err * channels; 340340 cptr -= err; 341341 if (cptr == 0) 342342 break; 343343 /* it is possible, that the initial buffer cannot store */ 344344 /* all data from the last period, so wait awhile */ 345345 err = wait_for_poll(handle, ufds, count); 346346 if (err < 0) { 347347 if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN || 348348 snd_pcm_state(handle) == SND_PCM_STATE_SUSPENDED) { 349349 err = snd_pcm_state(handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; 350350 if (xrun_recovery(handle, err) < 0) { 351351 printf("Write error: %s\n", snd_strerror(err)); 352352 exit(EXIT_FAILURE); 353353 } 354354 init = 1; 355355 } else { 356356 printf("Wait for poll failed\n"); 357357 return err; 358358 } 359359 } 360360 } 361361 } 362362 } 363363 364364 /* 365365 * Transfer method - asynchronous notification 366366 */ 367367 368368 struct async_private_data { 369369 signed short *samples; 370370 snd_pcm_channel_area_t *areas; 371371 double phase; 372372 }; 373373 374374 static void async_callback("a40">snd_async_handler_t *ahandler) 375375 { 376376 snd_pcm_t *handle = "a41">snd_async_handler_get_pcm(ahandler); 377377 struct async_private_data *data = "a42">snd_async_handler_get_callback_private(ahandler); 378378 signed short *samples = data->samples; 379379 snd_pcm_channel_area_t *areas = data->areas; 380380 snd_pcm_sframes_t avail; 381381 int err; 382382 383383 avail = "a43">snd_pcm_avail_update(handle); 384384 while (avail >= period_size) { 385385 generate_sine(areas, 0, period_size, &data->phase); 386386 err = snd_pcm_writei(handle, samples, period_size); 387387 if (err < 0) { 388388 printf("Initial write error: %s\n", snd_strerror(err)); 389389 exit(EXIT_FAILURE); 390390 } 391391 if (err != period_size) { 392392 printf("Initial write error: written %i expected %li\n", err, period_size); 393393 exit(EXIT_FAILURE); 394394 } 395395 avail = snd_pcm_avail_update(handle); 396396 } 397397 } 398398 399399 static int async_loop(snd_pcm_t *handle, 400400 signed short *samples, 401401 snd_pcm_channel_area_t *areas) 402402 { 403403 struct async_private_data data; 404404 snd_async_handler_t *ahandler; 405405 int err, count; 406406 407407 data.samples = samples; 408408 data.areas = areas; 409409 data.phase = 0; 410410 err = "a44">snd_async_add_pcm_handler(&ahandler, handle, async_callback, &data); 411411 if (err < 0) { 412412 printf("Unable to register async handler\n"); 413413 exit(EXIT_FAILURE); 414414 } 415415 for (count = 0; count < 2; count++) { 416416 generate_sine(areas, 0, period_size, &data.phase); 417417 err = snd_pcm_writei(handle, samples, period_size); 418418 if (err < 0) { 419419 printf("Initial write error: %s\n", snd_strerror(err)); 420420 exit(EXIT_FAILURE); 421421 } 422422 if (err != period_size) { 423423 printf("Initial write error: written %i expected %li\n", err, period_size); 424424 exit(EXIT_FAILURE); 425425 } 426426 } 427427 err = "a45">snd_pcm_start(handle); 428428 if (err < 0) { 429429 printf("Start error: %s\n", snd_strerror(err)); 430430 exit(EXIT_FAILURE); 431431 } 432432 433433 /* because all other work is done in the signal handler, 434434 suspend the process */ 435435 while (1) { 436436 sleep(1); 437437 } 438438 } 439439 440440 /* 441441 * Transfer method - asynchronous notification + direct write 442442 */ 443443 444444 static void async_direct_callback(snd_async_handler_t *ahandler) 445445 { 446446 snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); 447447 struct async_private_data *data = snd_async_handler_get_callback_private(ahandler); 448448 const snd_pcm_channel_area_t *my_areas; 449449 snd_pcm_uframes_t offset, frames, size; 450450 snd_pcm_sframes_t avail, commitres; 451451 "a46">snd_pcm_state_t state; 452452 int first = 0, err; 453453 454454 while (1) { 455455 state = snd_pcm_state(handle); 456456 if (state == SND_PCM_STATE_XRUN) { 457457 err = xrun_recovery(handle, -EPIPE); 458458 if (err < 0) { 459459 printf("XRUN recovery failed: %s\n", snd_strerror(err)); 460460 exit(EXIT_FAILURE); 461461 } 462462 first = 1; 463463 } else if (state == SND_PCM_STATE_SUSPENDED) { 464464 err = xrun_recovery(handle, -ESTRPIPE); 465465 if (err < 0) { 466466 printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); 467467 exit(EXIT_FAILURE); 468468 } 469469 } 470470 avail = snd_pcm_avail_update(handle); 471471 if (avail < 0) { 472472 err = xrun_recovery(handle, avail); 473473 if (err < 0) { 474474 printf("avail update failed: %s\n", snd_strerror(err)); 475475 exit(EXIT_FAILURE); 476476 } 477477 first = 1; 478478 continue; 479479 } 480480 if (avail < period_size) { 481481 if (first) { 482482 first = 0; 483483 err = snd_pcm_start(handle); 484484 if (err < 0) { 485485 printf("Start error: %s\n", snd_strerror(err)); 486486 exit(EXIT_FAILURE); 487487 } 488488 } else { 489489 break; 490490 } 491491 continue; 492492 } 493493 size = period_size; 494494 while (size > 0) { 495495 frames = size; 496496 err = "a47">snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); 497497 if (err < 0) { 498498 if ((err = xrun_recovery(handle, err)) < 0) { 499499 printf("MMAP begin avail error: %s\n", snd_strerror(err)); 500500 exit(EXIT_FAILURE); 501501 } 502502 first = 1; 503503 } 504504 generate_sine(my_areas, offset, frames, &data->phase); 505505 commitres = "a48">snd_pcm_mmap_commit(handle, offset, frames); 506506 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { 507507 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { 508508 printf("MMAP commit error: %s\n", snd_strerror(err)); 509509 exit(EXIT_FAILURE); 510510 } 511511 first = 1; 512512 } 513513 size -= frames; 514514 } 515515 } 516516 } 517517 518518 static int async_direct_loop(snd_pcm_t *handle, 519519 signed short *samples ATTRIBUTE_UNUSED, 520520 snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED) 521521 { 522522 struct async_private_data data; 523523 snd_async_handler_t *ahandler; 524524 const snd_pcm_channel_area_t *my_areas; 525525 snd_pcm_uframes_t offset, frames, size; 526526 snd_pcm_sframes_t commitres; 527527 int err, count; 528528 529529 data.samples = NULL; /* we do not require the global sample area for direct write */ 530530 data.areas = NULL; /* we do not require the global areas for direct write */ 531531 data.phase = 0; 532532 err = snd_async_add_pcm_handler(&ahandler, handle, async_direct_callback, &data); 533533 if (err < 0) { 534534 printf("Unable to register async handler\n"); 535535 exit(EXIT_FAILURE); 536536 } 537537 for (count = 0; count < 2; count++) { 538538 size = period_size; 539539 while (size > 0) { 540540 frames = size; 541541 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); 542542 if (err < 0) { 543543 if ((err = xrun_recovery(handle, err)) < 0) { 544544 printf("MMAP begin avail error: %s\n", snd_strerror(err)); 545545 exit(EXIT_FAILURE); 546546 } 547547 } 548548 generate_sine(my_areas, offset, frames, &data.phase); 549549 commitres = snd_pcm_mmap_commit(handle, offset, frames); 550550 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { 551551 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { 552552 printf("MMAP commit error: %s\n", snd_strerror(err)); 553553 exit(EXIT_FAILURE); 554554 } 555555 } 556556 size -= frames; 557557 } 558558 } 559559 err = snd_pcm_start(handle); 560560 if (err < 0) { 561561 printf("Start error: %s\n", snd_strerror(err)); 562562 exit(EXIT_FAILURE); 563563 } 564564 565565 /* because all other work is done in the signal handler, 566566 suspend the process */ 567567 while (1) { 568568 sleep(1); 569569 } 570570 } 571571 572572 /* 573573 * Transfer method - direct write only 574574 */ 575575 576576 static int direct_loop(snd_pcm_t *handle, 577577 signed short *samples ATTRIBUTE_UNUSED, 578578 snd_pcm_channel_area_t *areas ATTRIBUTE_UNUSED) 579579 { 580580 double phase = 0; 581581 const snd_pcm_channel_area_t *my_areas; 582582 snd_pcm_uframes_t offset, frames, size; 583583 snd_pcm_sframes_t avail, commitres; 584584 snd_pcm_state_t state; 585585 int err, first = 1; 586586 587587 while (1) { 588588 state = snd_pcm_state(handle); 589589 if (state == SND_PCM_STATE_XRUN) { 590590 err = xrun_recovery(handle, -EPIPE); 591591 if (err < 0) { 592592 printf("XRUN recovery failed: %s\n", snd_strerror(err)); 593593 return err; 594594 } 595595 first = 1; 596596 } else if (state == SND_PCM_STATE_SUSPENDED) { 597597 err = xrun_recovery(handle, -ESTRPIPE); 598598 if (err < 0) { 599599 printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); 600600 return err; 601601 } 602602 } 603603 avail = snd_pcm_avail_update(handle); 604604 if (avail < 0) { 605605 err = xrun_recovery(handle, avail); 606606 if (err < 0) { 607607 printf("avail update failed: %s\n", snd_strerror(err)); 608608 return err; 609609 } 610610 first = 1; 611611 continue; 612612 } 613613 if (avail < period_size) { 614614 if (first) { 615615 first = 0; 616616 err = snd_pcm_start(handle); 617617 if (err < 0) { 618618 printf("Start error: %s\n", snd_strerror(err)); 619619 exit(EXIT_FAILURE); 620620 } 621621 } else { 622622 err = "a49">snd_pcm_wait(handle, -1); 623623 if (err < 0) { 624624 if ((err = xrun_recovery(handle, err)) < 0) { 625625 printf("snd_pcm_wait error: %s\n", snd_strerror(err)); 626626 exit(EXIT_FAILURE); 627627 } 628628 first = 1; 629629 } 630630 } 631631 continue; 632632 } 633633 size = period_size; 634634 while (size > 0) { 635635 frames = size; 636636 err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); 637637 if (err < 0) { 638638 if ((err = xrun_recovery(handle, err)) < 0) { 639639 printf("MMAP begin avail error: %s\n", snd_strerror(err)); 640640 exit(EXIT_FAILURE); 641641 } 642642 first = 1; 643643 } 644644 generate_sine(my_areas, offset, frames, &phase); 645645 commitres = snd_pcm_mmap_commit(handle, offset, frames); 646646 if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { 647647 if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { 648648 printf("MMAP commit error: %s\n", snd_strerror(err)); 649649 exit(EXIT_FAILURE); 650650 } 651651 first = 1; 652652 } 653653 size -= frames; 654654 } 655655 } 656656 } 657657 658658 /* 659659 * Transfer method - direct write only using mmap_write functions 660660 */ 661661 662662 static int direct_write_loop(snd_pcm_t *handle, 663663 signed short *samples, 664664 snd_pcm_channel_area_t *areas) 665665 { 666666 double phase = 0; 667667 signed short *ptr; 668668 int err, cptr; 669669 670670 while (1) { 671671 generate_sine(areas, 0, period_size, &phase); 672672 ptr = samples; 673673 cptr = period_size; 674674 while (cptr > 0) { 675675 err = "a50">snd_pcm_mmap_writei(handle, ptr, cptr); 676676 if (err == -EAGAIN) 677677 continue; 678678 if (err < 0) { 679679 if (xrun_recovery(handle, err) < 0) { 680680 printf("Write error: %s\n", snd_strerror(err)); 681681 exit(EXIT_FAILURE); 682682 } 683683 break; /* skip one period */ 684684 } 685685 ptr += err * channels; 686686 cptr -= err; 687687 } 688688 } 689689 } 690690 691691 /* 692692 * 693693 */ 694694 695695 struct transfer_method { 696696 const char *name; 697697 snd_pcm_access_t access; 698698 int (*transfer_loop)(snd_pcm_t *handle, 699699 signed short *samples, 700700 snd_pcm_channel_area_t *areas); 701701 }; 702702 703703 static struct transfer_method transfer_methods[] = { 704704 { "write", "a51">SND_PCM_ACCESS_RW_INTERLEAVED, write_loop }, 705705 { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop }, 706706 { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop }, 707707 { "async_direct", "a52">SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop }, 708708 { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop }, 709709 { "direct_noninterleaved", "a53">SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop }, 710710 { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop }, 711711 { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL } 712712 }; 713713 714714 static void help(void) 715715 { 716716 int k; 717717 printf( 718718 "Usage: pcm [OPTION]... [FILE]...\n" 719719 "-h,--help help\n" 720720 "-D,--device playback device\n" 721721 "-r,--rate stream rate in Hz\n" 722722 "-c,--channels count of channels in stream\n" 723723 "-f,--frequency sine wave frequency in Hz\n" 724724 "-b,--buffer ring buffer size in us\n" 725725 "-p,--period period size in us\n" 726726 "-m,--method transfer method\n" 727727 "-o,--format sample format\n" 728728 "-v,--verbose show the PCM setup parameters\n" 729729 "-n,--noresample do not resample\n" 730730 "-e,--pevent enable poll event after each period\n" 731731 "\n"); 732732 printf("Recognized sample formats are:"); 733733 for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) { 734734 const char *s = "a54">snd_pcm_format_name(k); 735735 if (s) 736736 printf(" %s", s); 737737 } 738738 printf("\n"); 739739 printf("Recognized transfer methods are:"); 740740 for (k = 0; transfer_methods[k].name; k++) 741741 printf(" %s", transfer_methods[k].name); 742742 printf("\n"); 743743 } 744744 745745 int main(int argc, char *argv[]) 746746 { 747747 struct option long_option[] = 748748 { 749749 {"help", 0, NULL, 'h'}, 750750 {"device", 1, NULL, 'D'}, 751751 {"rate", 1, NULL, 'r'}, 752752 {"channels", 1, NULL, 'c'}, 753753 {"frequency", 1, NULL, 'f'}, 754754 {"buffer", 1, NULL, 'b'}, 755755 {"period", 1, NULL, 'p'}, 756756 {"method", 1, NULL, 'm'}, 757757 {"format", 1, NULL, 'o'}, 758758 {"verbose", 1, NULL, 'v'}, 759759 {"noresample", 1, NULL, 'n'}, 760760 {"pevent", 1, NULL, 'e'}, 761761 {NULL, 0, NULL, 0}, 762762 }; 763763 snd_pcm_t *handle; 764764 int err, morehelp; 765765 snd_pcm_hw_params_t *hwparams; 766766 snd_pcm_sw_params_t *swparams; 767767 int method = 0; 768768 signed short *samples; 769769 unsigned int chn; 770770 snd_pcm_channel_area_t *areas; 771771 772772 "a55">snd_pcm_hw_params_alloca(&hwparams); 773773 "a56">snd_pcm_sw_params_alloca(&swparams); 774774 775775 morehelp = 0; 776776 while (1) { 777777 int c; 778778 if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0) 779779 break; 780780 switch (c) { 781781 case 'h': 782782 morehelp++; 783783 break; 784784 case 'D': 785785 device = strdup(optarg); 786786 break; 787787 case 'r': 788788 rate = atoi(optarg); 789789 rate = rate < 4000 ? 4000 : rate; 790790 rate = rate > 196000 ? 196000 : rate; 791791 break; 792792 case 'c': 793793 channels = atoi(optarg); 794794 channels = channels < 1 ? 1 : channels; 795795 channels = channels > 1024 ? 1024 : channels; 796796 break; 797797 case 'f': 798798 freq = atoi(optarg); 799799 freq = freq < 50 ? 50 : freq; 800800 freq = freq > 5000 ? 5000 : freq; 801801 break; 802802 case 'b': 803803 buffer_time = atoi(optarg); 804804 buffer_time = buffer_time < 1000 ? 1000 : buffer_time; 805805 buffer_time = buffer_time > 1000000 ? 1000000 : buffer_time; 806806 break; 807807 case 'p': 808808 period_time = atoi(optarg); 809809 period_time = period_time < 1000 ? 1000 : period_time; 810810 period_time = period_time > 1000000 ? 1000000 : period_time; 811811 break; 812812 case 'm': 813813 for (method = 0; transfer_methods[method].name; method++) 814814 if (!strcasecmp(transfer_methods[method].name, optarg)) 815815 break; 816816 if (transfer_methods[method].name == NULL) 817817 method = 0; 818818 break; 819819 case 'o': 820820 for (format = 0; format < SND_PCM_FORMAT_LAST; format++) { 821821 const char *format_name = snd_pcm_format_name(format); 822822 if (format_name) 823823 if (!strcasecmp(format_name, optarg)) 824824 break; 825825 } 826826 if (format == SND_PCM_FORMAT_LAST) 827827 format = SND_PCM_FORMAT_S16; 828828 break; 829829 case 'v': 830830 verbose = 1; 831831 break; 832832 case 'n': 833833 resample = 0; 834834 break; 835835 case 'e': 836836 period_event = 1; 837837 break; 838838 } 839839 } 840840 841841 if (morehelp) { 842842 help(); 843843 return 0; 844844 } 845845 846846 err = "a57">snd_output_stdio_attach(&output, stdout, 0); 847847 if (err < 0) { 848848 printf("Output failed: %s\n", snd_strerror(err)); 849849 return 0; 850850 } 851851 852852 printf("Playback device is %s\n", device); 853853 printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels); 854854 printf("Sine wave rate is %.4fHz\n", freq); 855855 printf("Using transfer method: %s\n", transfer_methods[method].name); 856856 857857 if ((err = "a58">snd_pcm_open(&handle, device, "a59">SND_PCM_STREAM_PLAYBACK, 0)) < 0) { 858858 printf("Playback open error: %s\n", snd_strerror(err)); 859859 return 0; 860860 } 861861 862862 if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access)) < 0) { 863863 printf("Setting of hwparams failed: %s\n", snd_strerror(err)); 864864 exit(EXIT_FAILURE); 865865 } 866866 if ((err = set_swparams(handle, swparams)) < 0) { 867867 printf("Setting of swparams failed: %s\n", snd_strerror(err)); 868868 exit(EXIT_FAILURE); 869869 } 870870 871871 if (verbose > 0) 872872 "a60">snd_pcm_dump(handle, output); 873873 874874 samples = malloc((period_size * channels * "a61">snd_pcm_format_physical_width(format)) / 8); if (samples == NULL) { printf("No enough memory\n"); exit(EXIT_FAILURE); } areas = calloc(channels, sizeof(snd_pcm_channel_area_t)); if (areas == NULL) { printf("No enough memory\n"); exit(EXIT_FAILURE); } for (chn = 0; chn < channels; chn++) { areas[chn].addr = samples; areas[chn].first = chn * snd_pcm_format_physical_width(format); areas[chn].step = channels *