alsa.c (18179B)
1 /* 2 * Copyright (C) 2013-2015 Intel Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 16 #include <stdio.h> 17 #include <string.h> 18 #include <stdbool.h> 19 #include <stdint.h> 20 #include <pthread.h> 21 #include <errno.h> 22 23 #include <alsa/asoundlib.h> 24 25 #include "aconfig.h" 26 #include "gettext.h" 27 28 #include "common.h" 29 #include "alsa.h" 30 #include "latencytest.h" 31 32 struct pcm_container { 33 snd_pcm_t *handle; 34 snd_pcm_uframes_t period_size; 35 snd_pcm_uframes_t buffer_size; 36 snd_pcm_format_t format; 37 unsigned short channels; 38 size_t period_bytes; 39 size_t sample_bits; 40 size_t frame_bits; 41 char *buffer; 42 }; 43 44 struct format_map_table { 45 enum _bat_pcm_format format_bat; 46 snd_pcm_format_t format_alsa; 47 }; 48 49 static struct format_map_table map_tables[] = { 50 { BAT_PCM_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN }, 51 { BAT_PCM_FORMAT_U8, SND_PCM_FORMAT_U8 }, 52 { BAT_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_LE }, 53 { BAT_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3LE }, 54 { BAT_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_LE }, 55 { BAT_PCM_FORMAT_MAX, }, 56 }; 57 58 static int format_convert(struct bat *bat, snd_pcm_format_t *fmt) 59 { 60 struct format_map_table *t = map_tables; 61 62 for (; t->format_bat != BAT_PCM_FORMAT_MAX; t++) { 63 if (t->format_bat == bat->format) { 64 *fmt = t->format_alsa; 65 return 0; 66 } 67 } 68 fprintf(bat->err, _("Invalid format!\n")); 69 return -EINVAL; 70 } 71 72 static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm) 73 { 74 snd_pcm_hw_params_t *params; 75 snd_pcm_format_t format; 76 unsigned int buffer_time = 0; 77 unsigned int period_time = 0; 78 snd_pcm_uframes_t buffer_size = 0; 79 snd_pcm_uframes_t period_size = 0; 80 unsigned int rate; 81 int err; 82 const char *device_name = snd_pcm_name(sndpcm->handle); 83 84 /* Convert common format to ALSA format */ 85 err = format_convert(bat, &format); 86 if (err != 0) 87 return err; 88 89 /* Allocate a hardware parameters object. */ 90 snd_pcm_hw_params_alloca(¶ms); 91 92 /* Fill it in with default values. */ 93 err = snd_pcm_hw_params_any(sndpcm->handle, params); 94 if (err < 0) { 95 fprintf(bat->err, _("Set parameter to device error: ")); 96 fprintf(bat->err, _("default params: %s: %s(%d)\n"), 97 device_name, snd_strerror(err), err); 98 return err; 99 } 100 101 /* Set access mode */ 102 err = snd_pcm_hw_params_set_access(sndpcm->handle, params, 103 SND_PCM_ACCESS_RW_INTERLEAVED); 104 if (err < 0) { 105 fprintf(bat->err, _("Set parameter to device error: ")); 106 fprintf(bat->err, _("access type: %s: %s(%d)\n"), 107 device_name, snd_strerror(err), err); 108 return err; 109 } 110 111 /* Set format */ 112 err = snd_pcm_hw_params_set_format(sndpcm->handle, params, format); 113 if (err < 0) { 114 fprintf(bat->err, _("Set parameter to device error: ")); 115 fprintf(bat->err, _("PCM format: %d %s: %s(%d)\n"), format, 116 device_name, snd_strerror(err), err); 117 return err; 118 } 119 120 /* Set channels */ 121 err = snd_pcm_hw_params_set_channels(sndpcm->handle, 122 params, bat->channels); 123 if (err < 0) { 124 fprintf(bat->err, _("Set parameter to device error: ")); 125 fprintf(bat->err, _("channel number: %d %s: %s(%d)\n"), 126 bat->channels, 127 device_name, snd_strerror(err), err); 128 return err; 129 } 130 131 /* Set sampling rate */ 132 rate = bat->rate; 133 err = snd_pcm_hw_params_set_rate_near(sndpcm->handle, 134 params, &bat->rate, 135 0); 136 if (err < 0) { 137 fprintf(bat->err, _("Set parameter to device error: ")); 138 fprintf(bat->err, _("sample rate: %d %s: %s(%d)\n"), 139 bat->rate, 140 device_name, snd_strerror(err), err); 141 return err; 142 } 143 if ((float) rate * (1 + RATE_RANGE) < bat->rate 144 || (float) rate * (1 - RATE_RANGE) > bat->rate) { 145 fprintf(bat->err, _("Invalid parameters: sample rate: ")); 146 fprintf(bat->err, _("requested %dHz, got %dHz\n"), 147 rate, bat->rate); 148 return -EINVAL; 149 } 150 151 if (bat->buffer_size > 0 && bat->period_size == 0) 152 bat->period_size = bat->buffer_size / DIV_BUFFERSIZE; 153 154 if (bat->roundtriplatency && bat->buffer_size == 0) { 155 /* Set to minimum buffer size and period size 156 for latency test */ 157 if (snd_pcm_hw_params_get_buffer_size_min(params, 158 &buffer_size) < 0) { 159 fprintf(bat->err, 160 _("Get parameter from device error: ")); 161 fprintf(bat->err, _("buffer size min: %d %s: %s(%d)\n"), 162 (int) buffer_size, 163 device_name, snd_strerror(err), err); 164 return -EINVAL; 165 } 166 167 if (snd_pcm_hw_params_get_period_size_min(params, 168 &period_size, 0) < 0) { 169 fprintf(bat->err, 170 _("Get parameter from device error: ")); 171 fprintf(bat->err, _("period size min: %d %s: %s(%d)\n"), 172 (int) period_size, 173 device_name, snd_strerror(err), err); 174 return -EINVAL; 175 } 176 bat->buffer_size = (int) buffer_size; 177 bat->period_size = (int) period_size; 178 } 179 180 if (bat->buffer_size > 0) { 181 buffer_size = bat->buffer_size; 182 period_size = bat->period_size; 183 184 fprintf(bat->log, _("Set period size: %d buffer size: %d\n"), 185 (int) period_size, (int) buffer_size); 186 187 err = snd_pcm_hw_params_set_buffer_size_near(sndpcm->handle, 188 params, &buffer_size); 189 if (err < 0) { 190 fprintf(bat->err, _("Set parameter to device error: ")); 191 fprintf(bat->err, _("buffer size: %d %s: %s(%d)\n"), 192 (int) buffer_size, 193 device_name, snd_strerror(err), err); 194 return err; 195 } 196 197 err = snd_pcm_hw_params_set_period_size_near(sndpcm->handle, 198 params, &period_size, 0); 199 if (err < 0) { 200 fprintf(bat->err, _("Set parameter to device error: ")); 201 fprintf(bat->err, _("period size: %d %s: %s(%d)\n"), 202 (int) period_size, 203 device_name, snd_strerror(err), err); 204 return err; 205 } 206 } else { 207 if (snd_pcm_hw_params_get_buffer_time_max(params, 208 &buffer_time, 0) < 0) { 209 fprintf(bat->err, 210 _("Get parameter from device error: ")); 211 fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), 212 buffer_time, 213 device_name, snd_strerror(err), err); 214 return -EINVAL; 215 } 216 217 if (buffer_time > MAX_BUFFERTIME) 218 buffer_time = MAX_BUFFERTIME; 219 220 period_time = buffer_time / DIV_BUFFERTIME; 221 222 /* Set buffer time and period time */ 223 err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, 224 params, &buffer_time, 0); 225 if (err < 0) { 226 fprintf(bat->err, _("Set parameter to device error: ")); 227 fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"), 228 buffer_time, 229 device_name, snd_strerror(err), err); 230 return err; 231 } 232 233 err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, 234 params, &period_time, 0); 235 if (err < 0) { 236 fprintf(bat->err, _("Set parameter to device error: ")); 237 fprintf(bat->err, _("period time: %d %s: %s(%d)\n"), 238 period_time, 239 device_name, snd_strerror(err), err); 240 return err; 241 } 242 } 243 244 /* Write the parameters to the driver */ 245 if (snd_pcm_hw_params(sndpcm->handle, params) < 0) { 246 fprintf(bat->err, _("Set parameter to device error: ")); 247 fprintf(bat->err, _("hw params: %s: %s(%d)\n"), 248 device_name, snd_strerror(err), err); 249 return -EINVAL; 250 } 251 252 err = snd_pcm_hw_params_get_period_size(params, 253 &sndpcm->period_size, 0); 254 if (err < 0) { 255 fprintf(bat->err, _("Get parameter from device error: ")); 256 fprintf(bat->err, _("period size: %zd %s: %s(%d)\n"), 257 sndpcm->period_size, 258 device_name, snd_strerror(err), err); 259 return err; 260 } 261 262 err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size); 263 if (err < 0) { 264 fprintf(bat->err, _("Get parameter from device error: ")); 265 fprintf(bat->err, _("buffer size: %zd %s: %s(%d)\n"), 266 sndpcm->buffer_size, 267 device_name, snd_strerror(err), err); 268 return err; 269 } 270 271 if (sndpcm->period_size == sndpcm->buffer_size) { 272 fprintf(bat->err, _("Invalid parameters: can't use period ")); 273 fprintf(bat->err, _("equal to buffer size (%zd)\n"), 274 sndpcm->period_size); 275 return -EINVAL; 276 } 277 278 fprintf(bat->log, _("Get period size: %d buffer size: %d\n"), 279 (int) sndpcm->period_size, (int) sndpcm->buffer_size); 280 281 err = snd_pcm_format_physical_width(format); 282 if (err < 0) { 283 fprintf(bat->err, _("Invalid parameters: ")); 284 fprintf(bat->err, _("snd_pcm_format_physical_width: %d\n"), 285 err); 286 return err; 287 } 288 sndpcm->sample_bits = err; 289 290 sndpcm->frame_bits = sndpcm->sample_bits * bat->channels; 291 292 /* Calculate the period bytes */ 293 sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8; 294 sndpcm->buffer = (char *) malloc(sndpcm->period_bytes); 295 if (sndpcm->buffer == NULL) { 296 fprintf(bat->err, _("Not enough memory: size=%zd\n"), 297 sndpcm->period_bytes); 298 return -ENOMEM; 299 } 300 301 return 0; 302 } 303 304 static int write_to_pcm(const struct pcm_container *sndpcm, 305 int frames, struct bat *bat) 306 { 307 int err; 308 int offset = 0; 309 int remain = frames; 310 311 while (remain > 0) { 312 err = snd_pcm_writei(sndpcm->handle, sndpcm->buffer + offset, 313 remain); 314 if (err == -EAGAIN || (err >= 0 && err < frames)) { 315 snd_pcm_wait(sndpcm->handle, 500); 316 } else if (err == -EPIPE) { 317 fprintf(bat->err, _("Underrun: %s(%d)\n"), 318 snd_strerror(err), err); 319 if (bat->roundtriplatency) 320 bat->latency.xrun_error = true; 321 snd_pcm_prepare(sndpcm->handle); 322 } else if (err == -ESTRPIPE) { 323 while ((err = snd_pcm_resume(sndpcm->handle)) == -EAGAIN) 324 sleep(1); /* wait until resume flag is released */ 325 if (err < 0) 326 snd_pcm_prepare(sndpcm->handle); 327 } else if (err < 0) { 328 fprintf(bat->err, _("Write PCM device error: %s(%d)\n"), 329 snd_strerror(err), err); 330 return err; 331 } 332 333 if (err > 0) { 334 remain -= err; 335 offset += err * sndpcm->frame_bits / 8; 336 } 337 } 338 339 return 0; 340 } 341 342 /** 343 * Process output data for latency test 344 */ 345 static int latencytest_process_output(struct pcm_container *sndpcm, 346 struct bat *bat) 347 { 348 int err = 0; 349 int bytes = sndpcm->period_bytes; /* playback buffer size */ 350 int frames = sndpcm->period_size; /* frame count */ 351 352 bat->latency.is_playing = true; 353 354 while (1) { 355 /* generate output data */ 356 err = handleoutput(bat, sndpcm->buffer, bytes, frames); 357 if (err != 0) 358 break; 359 360 err = write_to_pcm(sndpcm, frames, bat); 361 if (err != 0) 362 break; 363 364 /* Xrun error, terminate the playback thread*/ 365 if (bat->latency.xrun_error == true) 366 break; 367 368 if (bat->latency.state == LATENCY_STATE_COMPLETE_SUCCESS) 369 break; 370 371 bat->periods_played++; 372 } 373 374 bat->latency.is_playing = false; 375 376 return err; 377 } 378 379 static int write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat) 380 { 381 int err = 0; 382 int bytes = sndpcm->period_bytes; /* playback buffer size */ 383 int frames = bytes * 8 / sndpcm->frame_bits; /* frame count */ 384 FILE *fp = NULL; 385 int bytes_total = 0; 386 387 if (bat->debugplay) { 388 fp = fopen(bat->debugplay, "wb"); 389 err = -errno; 390 if (fp == NULL) { 391 fprintf(bat->err, _("Cannot open file: %s %d\n"), 392 bat->debugplay, err); 393 return err; 394 } 395 /* leave space for wav header */ 396 if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 397 err = -errno; 398 fclose(fp); 399 return err; 400 } 401 } 402 403 while (1) { 404 err = generate_input_data(bat, sndpcm->buffer, bytes, frames); 405 if (err != 0) 406 break; 407 408 if (bat->debugplay) { 409 if (fwrite(sndpcm->buffer, 1, bytes, fp) != bytes) { 410 err = -EIO; 411 break; 412 } 413 bytes_total += bytes; 414 } 415 416 bat->periods_played++; 417 if (bat->period_is_limited 418 && bat->periods_played >= bat->periods_total) 419 break; 420 421 err = write_to_pcm(sndpcm, frames, bat); 422 if (err != 0) 423 break; 424 } 425 426 if (bat->debugplay) { 427 update_wav_header(bat, fp, bytes_total); 428 fclose(fp); 429 } 430 431 snd_pcm_drain(sndpcm->handle); 432 433 return err; 434 } 435 436 /** 437 * Play 438 */ 439 void *playback_alsa(struct bat *bat) 440 { 441 int err = 0; 442 struct pcm_container sndpcm; 443 444 fprintf(bat->log, _("Entering playback thread (ALSA).\n")); 445 446 retval_play = 0; 447 memset(&sndpcm, 0, sizeof(sndpcm)); 448 449 err = snd_pcm_open(&sndpcm.handle, bat->playback.device, 450 SND_PCM_STREAM_PLAYBACK, 0); 451 if (err != 0) { 452 fprintf(bat->err, _("Cannot open PCM playback device: ")); 453 fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err); 454 retval_play = err; 455 goto exit1; 456 } 457 458 err = set_snd_pcm_params(bat, &sndpcm); 459 if (err != 0) { 460 retval_play = err; 461 goto exit2; 462 } 463 464 if (bat->playback.file == NULL) { 465 fprintf(bat->log, _("Playing generated audio sine wave")); 466 bat->sinus_duration == 0 ? 467 fprintf(bat->log, _(" endlessly\n")) : 468 fprintf(bat->log, _("\n")); 469 } else { 470 fprintf(bat->log, _("Playing input audio file: %s\n"), 471 bat->playback.file); 472 bat->fp = fopen(bat->playback.file, "rb"); 473 err = -errno; 474 if (bat->fp == NULL) { 475 fprintf(bat->err, _("Cannot open file: %s %d\n"), 476 bat->playback.file, err); 477 retval_play = err; 478 goto exit3; 479 } 480 /* Skip header */ 481 err = read_wav_header(bat, bat->playback.file, bat->fp, true); 482 if (err != 0) { 483 retval_play = err; 484 goto exit4; 485 } 486 } 487 488 if (bat->roundtriplatency) 489 err = latencytest_process_output(&sndpcm, bat); 490 else 491 err = write_to_pcm_loop(&sndpcm, bat); 492 if (err < 0) { 493 retval_play = err; 494 goto exit4; 495 } 496 497 exit4: 498 if (bat->playback.file) 499 fclose(bat->fp); 500 exit3: 501 free(sndpcm.buffer); 502 exit2: 503 snd_pcm_close(sndpcm.handle); 504 exit1: 505 pthread_exit(&retval_play); 506 } 507 508 static int read_from_pcm(struct pcm_container *sndpcm, 509 int frames, struct bat *bat) 510 { 511 int err = 0; 512 int offset = 0; 513 int remain = frames; 514 515 while (remain > 0) { 516 err = snd_pcm_readi(sndpcm->handle, 517 sndpcm->buffer + offset, remain); 518 if (err == -EAGAIN || (err >= 0 && err < remain)) { 519 snd_pcm_wait(sndpcm->handle, 500); 520 } else if (err == -EPIPE) { 521 snd_pcm_prepare(sndpcm->handle); 522 fprintf(bat->err, _("Overrun: %s(%d)\n"), 523 snd_strerror(err), err); 524 if (bat->roundtriplatency) 525 bat->latency.xrun_error = true; 526 } else if (err == -ESTRPIPE) { 527 while ((err = snd_pcm_resume(sndpcm->handle)) == -EAGAIN) 528 sleep(1); /* wait until resume flag is released */ 529 if (err < 0) 530 snd_pcm_prepare(sndpcm->handle); 531 } else if (err < 0) { 532 fprintf(bat->err, _("Read PCM device error: %s(%d)\n"), 533 snd_strerror(err), err); 534 return err; 535 } 536 537 if (err > 0) { 538 remain -= err; 539 offset += err * sndpcm->frame_bits / 8; 540 } 541 } 542 543 return 0; 544 } 545 546 static int read_from_pcm_loop(struct pcm_container *sndpcm, struct bat *bat) 547 { 548 int err = 0; 549 FILE *fp = NULL; 550 int size, frames; 551 int bytes_read = 0; 552 int bytes_count = bat->frames * bat->frame_size; 553 int remain = bytes_count; 554 555 remove(bat->capture.file); 556 fp = fopen(bat->capture.file, "wb"); 557 err = -errno; 558 if (fp == NULL) { 559 fprintf(bat->err, _("Cannot open file: %s %d\n"), 560 bat->capture.file, err); 561 return err; 562 } 563 /* leave space for file header */ 564 if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 565 err = -errno; 566 fclose(fp); 567 return err; 568 } 569 570 while (remain > 0) { 571 size = (remain <= sndpcm->period_bytes) ? 572 remain : sndpcm->period_bytes; 573 frames = size * 8 / sndpcm->frame_bits; 574 575 /* read a chunk from pcm device */ 576 err = read_from_pcm(sndpcm, frames, bat); 577 if (err != 0) 578 break; 579 580 /* write the chunk to file */ 581 if (fwrite(sndpcm->buffer, 1, size, fp) != size) { 582 err = -EIO; 583 break; 584 } 585 586 bytes_read += size; 587 remain -= size; 588 bat->periods_played++; 589 590 if (bat->period_is_limited 591 && bat->periods_played >= bat->periods_total) 592 break; 593 } 594 595 update_wav_header(bat, fp, bytes_read); 596 597 fclose(fp); 598 return err; 599 } 600 601 /** 602 * Process input data for latency test 603 */ 604 static int latencytest_process_input(struct pcm_container *sndpcm, 605 struct bat *bat) 606 { 607 int err = 0; 608 FILE *fp = NULL; 609 int bytes_read = 0; 610 int frames = sndpcm->period_size; 611 int size = sndpcm->period_bytes; 612 int bytes_count = bat->frames * bat->frame_size; 613 614 remove(bat->capture.file); 615 fp = fopen(bat->capture.file, "wb"); 616 err = -errno; 617 if (fp == NULL) { 618 fprintf(bat->err, _("Cannot open file: %s %d\n"), 619 bat->capture.file, err); 620 return err; 621 } 622 /* leave space for file header */ 623 if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) { 624 fclose(fp); 625 return err; 626 } 627 628 bat->latency.is_capturing = true; 629 630 while (bytes_read < bytes_count) { 631 /* read a chunk from pcm device */ 632 err = read_from_pcm(sndpcm, frames, bat); 633 if (err != 0) 634 break; 635 636 /* Xrun error, terminate the capture thread*/ 637 if (bat->latency.xrun_error == true) 638 break; 639 640 err = handleinput(bat, sndpcm->buffer, frames); 641 if (err != 0) 642 break; 643 644 if (bat->latency.is_playing == false) 645 break; 646 647 /* write the chunk to file */ 648 if (fwrite(sndpcm->buffer, 1, size, fp) != size) { 649 err = -EIO; 650 break; 651 } 652 653 bytes_read += size; 654 } 655 656 bat->latency.is_capturing = false; 657 658 update_wav_header(bat, fp, bytes_read); 659 660 fclose(fp); 661 return err; 662 } 663 664 665 static void pcm_cleanup(void *p) 666 { 667 snd_pcm_close(p); 668 } 669 670 /** 671 * Record 672 */ 673 void *record_alsa(struct bat *bat) 674 { 675 int err = 0; 676 struct pcm_container sndpcm; 677 678 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 679 680 fprintf(bat->log, _("Entering capture thread (ALSA).\n")); 681 682 retval_record = 0; 683 memset(&sndpcm, 0, sizeof(sndpcm)); 684 685 err = snd_pcm_open(&sndpcm.handle, bat->capture.device, 686 SND_PCM_STREAM_CAPTURE, 0); 687 if (err != 0) { 688 fprintf(bat->err, _("Cannot open PCM capture device: ")); 689 fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err); 690 retval_record = err; 691 goto exit1; 692 } 693 694 err = set_snd_pcm_params(bat, &sndpcm); 695 if (err != 0) { 696 retval_record = err; 697 goto exit2; 698 } 699 700 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 701 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 702 pthread_cleanup_push(pcm_cleanup, sndpcm.handle); 703 pthread_cleanup_push(free, sndpcm.buffer); 704 705 fprintf(bat->log, _("Recording ...\n")); 706 if (bat->roundtriplatency) 707 err = latencytest_process_input(&sndpcm, bat); 708 else 709 err = read_from_pcm_loop(&sndpcm, bat); 710 if (err != 0) { 711 retval_record = err; 712 goto exit3; 713 } 714 715 /* Normally we will never reach this part of code (unless error in 716 * previous call) (before exit3) as this thread will be cancelled 717 * by end of play thread. Except in single line mode. */ 718 pthread_cleanup_pop(0); 719 pthread_cleanup_pop(0); 720 721 snd_pcm_drain(sndpcm.handle); 722 pthread_exit(&retval_record); 723 724 exit3: 725 free(sndpcm.buffer); 726 exit2: 727 snd_pcm_close(sndpcm.handle); 728 exit1: 729 pthread_exit(&retval_record); 730 }