alsaaudio.c (24871B)
1/* 2 * QEMU ALSA audio driver 3 * 4 * Copyright (c) 2005 Vassili Karpov (malc) 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25#include "qemu/osdep.h" 26#include <alsa/asoundlib.h> 27#include "qemu/main-loop.h" 28#include "qemu/module.h" 29#include "audio.h" 30#include "trace.h" 31 32#pragma GCC diagnostic ignored "-Waddress" 33 34#define AUDIO_CAP "alsa" 35#include "audio_int.h" 36 37#define DEBUG_ALSA 0 38 39struct pollhlp { 40 snd_pcm_t *handle; 41 struct pollfd *pfds; 42 int count; 43 int mask; 44 AudioState *s; 45}; 46 47typedef struct ALSAVoiceOut { 48 HWVoiceOut hw; 49 snd_pcm_t *handle; 50 struct pollhlp pollhlp; 51 Audiodev *dev; 52} ALSAVoiceOut; 53 54typedef struct ALSAVoiceIn { 55 HWVoiceIn hw; 56 snd_pcm_t *handle; 57 struct pollhlp pollhlp; 58 Audiodev *dev; 59} ALSAVoiceIn; 60 61struct alsa_params_req { 62 int freq; 63 snd_pcm_format_t fmt; 64 int nchannels; 65}; 66 67struct alsa_params_obt { 68 int freq; 69 AudioFormat fmt; 70 int endianness; 71 int nchannels; 72 snd_pcm_uframes_t samples; 73}; 74 75static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...) 76{ 77 va_list ap; 78 79 va_start (ap, fmt); 80 AUD_vlog (AUDIO_CAP, fmt, ap); 81 va_end (ap); 82 83 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err)); 84} 85 86static void GCC_FMT_ATTR (3, 4) alsa_logerr2 ( 87 int err, 88 const char *typ, 89 const char *fmt, 90 ... 91 ) 92{ 93 va_list ap; 94 95 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); 96 97 va_start (ap, fmt); 98 AUD_vlog (AUDIO_CAP, fmt, ap); 99 va_end (ap); 100 101 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err)); 102} 103 104static void alsa_fini_poll (struct pollhlp *hlp) 105{ 106 int i; 107 struct pollfd *pfds = hlp->pfds; 108 109 if (pfds) { 110 for (i = 0; i < hlp->count; ++i) { 111 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL); 112 } 113 g_free (pfds); 114 } 115 hlp->pfds = NULL; 116 hlp->count = 0; 117 hlp->handle = NULL; 118} 119 120static void alsa_anal_close1 (snd_pcm_t **handlep) 121{ 122 int err = snd_pcm_close (*handlep); 123 if (err) { 124 alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep); 125 } 126 *handlep = NULL; 127} 128 129static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp) 130{ 131 alsa_fini_poll (hlp); 132 alsa_anal_close1 (handlep); 133} 134 135static int alsa_recover (snd_pcm_t *handle) 136{ 137 int err = snd_pcm_prepare (handle); 138 if (err < 0) { 139 alsa_logerr (err, "Failed to prepare handle %p\n", handle); 140 return -1; 141 } 142 return 0; 143} 144 145static int alsa_resume (snd_pcm_t *handle) 146{ 147 int err = snd_pcm_resume (handle); 148 if (err < 0) { 149 alsa_logerr (err, "Failed to resume handle %p\n", handle); 150 return -1; 151 } 152 return 0; 153} 154 155static void alsa_poll_handler (void *opaque) 156{ 157 int err, count; 158 snd_pcm_state_t state; 159 struct pollhlp *hlp = opaque; 160 unsigned short revents; 161 162 count = poll (hlp->pfds, hlp->count, 0); 163 if (count < 0) { 164 dolog ("alsa_poll_handler: poll %s\n", strerror (errno)); 165 return; 166 } 167 168 if (!count) { 169 return; 170 } 171 172 /* XXX: ALSA example uses initial count, not the one returned by 173 poll, correct? */ 174 err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds, 175 hlp->count, &revents); 176 if (err < 0) { 177 alsa_logerr (err, "snd_pcm_poll_descriptors_revents"); 178 return; 179 } 180 181 if (!(revents & hlp->mask)) { 182 trace_alsa_revents(revents); 183 return; 184 } 185 186 state = snd_pcm_state (hlp->handle); 187 switch (state) { 188 case SND_PCM_STATE_SETUP: 189 alsa_recover (hlp->handle); 190 break; 191 192 case SND_PCM_STATE_XRUN: 193 alsa_recover (hlp->handle); 194 break; 195 196 case SND_PCM_STATE_SUSPENDED: 197 alsa_resume (hlp->handle); 198 break; 199 200 case SND_PCM_STATE_PREPARED: 201 audio_run(hlp->s, "alsa run (prepared)"); 202 break; 203 204 case SND_PCM_STATE_RUNNING: 205 audio_run(hlp->s, "alsa run (running)"); 206 break; 207 208 default: 209 dolog ("Unexpected state %d\n", state); 210 } 211} 212 213static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask) 214{ 215 int i, count, err; 216 struct pollfd *pfds; 217 218 count = snd_pcm_poll_descriptors_count (handle); 219 if (count <= 0) { 220 dolog ("Could not initialize poll mode\n" 221 "Invalid number of poll descriptors %d\n", count); 222 return -1; 223 } 224 225 pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds)); 226 if (!pfds) { 227 dolog ("Could not initialize poll mode\n"); 228 return -1; 229 } 230 231 err = snd_pcm_poll_descriptors (handle, pfds, count); 232 if (err < 0) { 233 alsa_logerr (err, "Could not initialize poll mode\n" 234 "Could not obtain poll descriptors\n"); 235 g_free (pfds); 236 return -1; 237 } 238 239 for (i = 0; i < count; ++i) { 240 if (pfds[i].events & POLLIN) { 241 qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp); 242 } 243 if (pfds[i].events & POLLOUT) { 244 trace_alsa_pollout(i, pfds[i].fd); 245 qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp); 246 } 247 trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err); 248 249 } 250 hlp->pfds = pfds; 251 hlp->count = count; 252 hlp->handle = handle; 253 hlp->mask = mask; 254 return 0; 255} 256 257static int alsa_poll_out (HWVoiceOut *hw) 258{ 259 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; 260 261 return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT); 262} 263 264static int alsa_poll_in (HWVoiceIn *hw) 265{ 266 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; 267 268 return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN); 269} 270 271static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness) 272{ 273 switch (fmt) { 274 case AUDIO_FORMAT_S8: 275 return SND_PCM_FORMAT_S8; 276 277 case AUDIO_FORMAT_U8: 278 return SND_PCM_FORMAT_U8; 279 280 case AUDIO_FORMAT_S16: 281 if (endianness) { 282 return SND_PCM_FORMAT_S16_BE; 283 } else { 284 return SND_PCM_FORMAT_S16_LE; 285 } 286 287 case AUDIO_FORMAT_U16: 288 if (endianness) { 289 return SND_PCM_FORMAT_U16_BE; 290 } else { 291 return SND_PCM_FORMAT_U16_LE; 292 } 293 294 case AUDIO_FORMAT_S32: 295 if (endianness) { 296 return SND_PCM_FORMAT_S32_BE; 297 } else { 298 return SND_PCM_FORMAT_S32_LE; 299 } 300 301 case AUDIO_FORMAT_U32: 302 if (endianness) { 303 return SND_PCM_FORMAT_U32_BE; 304 } else { 305 return SND_PCM_FORMAT_U32_LE; 306 } 307 308 case AUDIO_FORMAT_F32: 309 if (endianness) { 310 return SND_PCM_FORMAT_FLOAT_BE; 311 } else { 312 return SND_PCM_FORMAT_FLOAT_LE; 313 } 314 315 default: 316 dolog ("Internal logic error: Bad audio format %d\n", fmt); 317#ifdef DEBUG_AUDIO 318 abort (); 319#endif 320 return SND_PCM_FORMAT_U8; 321 } 322} 323 324static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt, 325 int *endianness) 326{ 327 switch (alsafmt) { 328 case SND_PCM_FORMAT_S8: 329 *endianness = 0; 330 *fmt = AUDIO_FORMAT_S8; 331 break; 332 333 case SND_PCM_FORMAT_U8: 334 *endianness = 0; 335 *fmt = AUDIO_FORMAT_U8; 336 break; 337 338 case SND_PCM_FORMAT_S16_LE: 339 *endianness = 0; 340 *fmt = AUDIO_FORMAT_S16; 341 break; 342 343 case SND_PCM_FORMAT_U16_LE: 344 *endianness = 0; 345 *fmt = AUDIO_FORMAT_U16; 346 break; 347 348 case SND_PCM_FORMAT_S16_BE: 349 *endianness = 1; 350 *fmt = AUDIO_FORMAT_S16; 351 break; 352 353 case SND_PCM_FORMAT_U16_BE: 354 *endianness = 1; 355 *fmt = AUDIO_FORMAT_U16; 356 break; 357 358 case SND_PCM_FORMAT_S32_LE: 359 *endianness = 0; 360 *fmt = AUDIO_FORMAT_S32; 361 break; 362 363 case SND_PCM_FORMAT_U32_LE: 364 *endianness = 0; 365 *fmt = AUDIO_FORMAT_U32; 366 break; 367 368 case SND_PCM_FORMAT_S32_BE: 369 *endianness = 1; 370 *fmt = AUDIO_FORMAT_S32; 371 break; 372 373 case SND_PCM_FORMAT_U32_BE: 374 *endianness = 1; 375 *fmt = AUDIO_FORMAT_U32; 376 break; 377 378 case SND_PCM_FORMAT_FLOAT_LE: 379 *endianness = 0; 380 *fmt = AUDIO_FORMAT_F32; 381 break; 382 383 case SND_PCM_FORMAT_FLOAT_BE: 384 *endianness = 1; 385 *fmt = AUDIO_FORMAT_F32; 386 break; 387 388 default: 389 dolog ("Unrecognized audio format %d\n", alsafmt); 390 return -1; 391 } 392 393 return 0; 394} 395 396static void alsa_dump_info (struct alsa_params_req *req, 397 struct alsa_params_obt *obt, 398 snd_pcm_format_t obtfmt, 399 AudiodevAlsaPerDirectionOptions *apdo) 400{ 401 dolog("parameter | requested value | obtained value\n"); 402 dolog("format | %10d | %10d\n", req->fmt, obtfmt); 403 dolog("channels | %10d | %10d\n", 404 req->nchannels, obt->nchannels); 405 dolog("frequency | %10d | %10d\n", req->freq, obt->freq); 406 dolog("============================================\n"); 407 dolog("requested: buffer len %" PRId32 " period len %" PRId32 "\n", 408 apdo->buffer_length, apdo->period_length); 409 dolog("obtained: samples %ld\n", obt->samples); 410} 411 412static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) 413{ 414 int err; 415 snd_pcm_sw_params_t *sw_params; 416 417 snd_pcm_sw_params_alloca (&sw_params); 418 419 err = snd_pcm_sw_params_current (handle, sw_params); 420 if (err < 0) { 421 dolog ("Could not fully initialize DAC\n"); 422 alsa_logerr (err, "Failed to get current software parameters\n"); 423 return; 424 } 425 426 err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold); 427 if (err < 0) { 428 dolog ("Could not fully initialize DAC\n"); 429 alsa_logerr (err, "Failed to set software threshold to %ld\n", 430 threshold); 431 return; 432 } 433 434 err = snd_pcm_sw_params (handle, sw_params); 435 if (err < 0) { 436 dolog ("Could not fully initialize DAC\n"); 437 alsa_logerr (err, "Failed to set software parameters\n"); 438 return; 439 } 440} 441 442static int alsa_open(bool in, struct alsa_params_req *req, 443 struct alsa_params_obt *obt, snd_pcm_t **handlep, 444 Audiodev *dev) 445{ 446 AudiodevAlsaOptions *aopts = &dev->u.alsa; 447 AudiodevAlsaPerDirectionOptions *apdo = in ? aopts->in : aopts->out; 448 snd_pcm_t *handle; 449 snd_pcm_hw_params_t *hw_params; 450 int err; 451 unsigned int freq, nchannels; 452 const char *pcm_name = apdo->has_dev ? apdo->dev : "default"; 453 snd_pcm_uframes_t obt_buffer_size; 454 const char *typ = in ? "ADC" : "DAC"; 455 snd_pcm_format_t obtfmt; 456 457 freq = req->freq; 458 nchannels = req->nchannels; 459 460 snd_pcm_hw_params_alloca (&hw_params); 461 462 err = snd_pcm_open ( 463 &handle, 464 pcm_name, 465 in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 466 SND_PCM_NONBLOCK 467 ); 468 if (err < 0) { 469 alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name); 470 return -1; 471 } 472 473 err = snd_pcm_hw_params_any (handle, hw_params); 474 if (err < 0) { 475 alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n"); 476 goto err; 477 } 478 479 err = snd_pcm_hw_params_set_access ( 480 handle, 481 hw_params, 482 SND_PCM_ACCESS_RW_INTERLEAVED 483 ); 484 if (err < 0) { 485 alsa_logerr2 (err, typ, "Failed to set access type\n"); 486 goto err; 487 } 488 489 err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt); 490 if (err < 0) { 491 alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt); 492 } 493 494 err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0); 495 if (err < 0) { 496 alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq); 497 goto err; 498 } 499 500 err = snd_pcm_hw_params_set_channels_near ( 501 handle, 502 hw_params, 503 &nchannels 504 ); 505 if (err < 0) { 506 alsa_logerr2 (err, typ, "Failed to set number of channels %d\n", 507 req->nchannels); 508 goto err; 509 } 510 511 if (apdo->buffer_length) { 512 int dir = 0; 513 unsigned int btime = apdo->buffer_length; 514 515 err = snd_pcm_hw_params_set_buffer_time_near( 516 handle, hw_params, &btime, &dir); 517 518 if (err < 0) { 519 alsa_logerr2(err, typ, "Failed to set buffer time to %" PRId32 "\n", 520 apdo->buffer_length); 521 goto err; 522 } 523 524 if (apdo->has_buffer_length && btime != apdo->buffer_length) { 525 dolog("Requested buffer time %" PRId32 526 " was rejected, using %u\n", apdo->buffer_length, btime); 527 } 528 } 529 530 if (apdo->period_length) { 531 int dir = 0; 532 unsigned int ptime = apdo->period_length; 533 534 err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &ptime, 535 &dir); 536 537 if (err < 0) { 538 alsa_logerr2(err, typ, "Failed to set period time to %" PRId32 "\n", 539 apdo->period_length); 540 goto err; 541 } 542 543 if (apdo->has_period_length && ptime != apdo->period_length) { 544 dolog("Requested period time %" PRId32 " was rejected, using %d\n", 545 apdo->period_length, ptime); 546 } 547 } 548 549 err = snd_pcm_hw_params (handle, hw_params); 550 if (err < 0) { 551 alsa_logerr2 (err, typ, "Failed to apply audio parameters\n"); 552 goto err; 553 } 554 555 err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size); 556 if (err < 0) { 557 alsa_logerr2 (err, typ, "Failed to get buffer size\n"); 558 goto err; 559 } 560 561 err = snd_pcm_hw_params_get_format (hw_params, &obtfmt); 562 if (err < 0) { 563 alsa_logerr2 (err, typ, "Failed to get format\n"); 564 goto err; 565 } 566 567 if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) { 568 dolog ("Invalid format was returned %d\n", obtfmt); 569 goto err; 570 } 571 572 err = snd_pcm_prepare (handle); 573 if (err < 0) { 574 alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle); 575 goto err; 576 } 577 578 if (!in && aopts->has_threshold && aopts->threshold) { 579 struct audsettings as = { .freq = freq }; 580 alsa_set_threshold( 581 handle, 582 audio_buffer_frames(qapi_AudiodevAlsaPerDirectionOptions_base(apdo), 583 &as, aopts->threshold)); 584 } 585 586 obt->nchannels = nchannels; 587 obt->freq = freq; 588 obt->samples = obt_buffer_size; 589 590 *handlep = handle; 591 592 if (DEBUG_ALSA || obtfmt != req->fmt || 593 obt->nchannels != req->nchannels || obt->freq != req->freq) { 594 dolog ("Audio parameters for %s\n", typ); 595 alsa_dump_info(req, obt, obtfmt, apdo); 596 } 597 598 return 0; 599 600 err: 601 alsa_anal_close1 (&handle); 602 return -1; 603} 604 605static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len) 606{ 607 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; 608 size_t pos = 0; 609 size_t len_frames = len / hw->info.bytes_per_frame; 610 611 while (len_frames) { 612 char *src = advance(buf, pos); 613 snd_pcm_sframes_t written; 614 615 written = snd_pcm_writei(alsa->handle, src, len_frames); 616 617 if (written <= 0) { 618 switch (written) { 619 case 0: 620 trace_alsa_wrote_zero(len_frames); 621 return pos; 622 623 case -EPIPE: 624 if (alsa_recover(alsa->handle)) { 625 alsa_logerr(written, "Failed to write %zu frames\n", 626 len_frames); 627 return pos; 628 } 629 trace_alsa_xrun_out(); 630 continue; 631 632 case -ESTRPIPE: 633 /* 634 * stream is suspended and waiting for an application 635 * recovery 636 */ 637 if (alsa_resume(alsa->handle)) { 638 alsa_logerr(written, "Failed to write %zu frames\n", 639 len_frames); 640 return pos; 641 } 642 trace_alsa_resume_out(); 643 continue; 644 645 case -EAGAIN: 646 return pos; 647 648 default: 649 alsa_logerr(written, "Failed to write %zu frames from %p\n", 650 len, src); 651 return pos; 652 } 653 } 654 655 pos += written * hw->info.bytes_per_frame; 656 if (written < len_frames) { 657 break; 658 } 659 len_frames -= written; 660 } 661 662 return pos; 663} 664 665static void alsa_fini_out (HWVoiceOut *hw) 666{ 667 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; 668 669 ldebug ("alsa_fini\n"); 670 alsa_anal_close (&alsa->handle, &alsa->pollhlp); 671} 672 673static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as, 674 void *drv_opaque) 675{ 676 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; 677 struct alsa_params_req req; 678 struct alsa_params_obt obt; 679 snd_pcm_t *handle; 680 struct audsettings obt_as; 681 Audiodev *dev = drv_opaque; 682 683 req.fmt = aud_to_alsafmt (as->fmt, as->endianness); 684 req.freq = as->freq; 685 req.nchannels = as->nchannels; 686 687 if (alsa_open(0, &req, &obt, &handle, dev)) { 688 return -1; 689 } 690 691 obt_as.freq = obt.freq; 692 obt_as.nchannels = obt.nchannels; 693 obt_as.fmt = obt.fmt; 694 obt_as.endianness = obt.endianness; 695 696 audio_pcm_init_info (&hw->info, &obt_as); 697 hw->samples = obt.samples; 698 699 alsa->pollhlp.s = hw->s; 700 alsa->handle = handle; 701 alsa->dev = dev; 702 return 0; 703} 704 705#define VOICE_CTL_PAUSE 0 706#define VOICE_CTL_PREPARE 1 707#define VOICE_CTL_START 2 708 709static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl) 710{ 711 int err; 712 713 if (ctl == VOICE_CTL_PAUSE) { 714 err = snd_pcm_drop (handle); 715 if (err < 0) { 716 alsa_logerr (err, "Could not stop %s\n", typ); 717 return -1; 718 } 719 } else { 720 err = snd_pcm_prepare (handle); 721 if (err < 0) { 722 alsa_logerr (err, "Could not prepare handle for %s\n", typ); 723 return -1; 724 } 725 if (ctl == VOICE_CTL_START) { 726 err = snd_pcm_start(handle); 727 if (err < 0) { 728 alsa_logerr (err, "Could not start handle for %s\n", typ); 729 return -1; 730 } 731 } 732 } 733 734 return 0; 735} 736 737static void alsa_enable_out(HWVoiceOut *hw, bool enable) 738{ 739 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; 740 AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out; 741 742 if (enable) { 743 bool poll_mode = apdo->try_poll; 744 745 ldebug("enabling voice\n"); 746 if (poll_mode && alsa_poll_out(hw)) { 747 poll_mode = 0; 748 } 749 hw->poll_mode = poll_mode; 750 alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PREPARE); 751 } else { 752 ldebug("disabling voice\n"); 753 if (hw->poll_mode) { 754 hw->poll_mode = 0; 755 alsa_fini_poll(&alsa->pollhlp); 756 } 757 alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PAUSE); 758 } 759} 760 761static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 762{ 763 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; 764 struct alsa_params_req req; 765 struct alsa_params_obt obt; 766 snd_pcm_t *handle; 767 struct audsettings obt_as; 768 Audiodev *dev = drv_opaque; 769 770 req.fmt = aud_to_alsafmt (as->fmt, as->endianness); 771 req.freq = as->freq; 772 req.nchannels = as->nchannels; 773 774 if (alsa_open(1, &req, &obt, &handle, dev)) { 775 return -1; 776 } 777 778 obt_as.freq = obt.freq; 779 obt_as.nchannels = obt.nchannels; 780 obt_as.fmt = obt.fmt; 781 obt_as.endianness = obt.endianness; 782 783 audio_pcm_init_info (&hw->info, &obt_as); 784 hw->samples = obt.samples; 785 786 alsa->pollhlp.s = hw->s; 787 alsa->handle = handle; 788 alsa->dev = dev; 789 return 0; 790} 791 792static void alsa_fini_in (HWVoiceIn *hw) 793{ 794 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; 795 796 alsa_anal_close (&alsa->handle, &alsa->pollhlp); 797} 798 799static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len) 800{ 801 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; 802 size_t pos = 0; 803 804 while (len) { 805 void *dst = advance(buf, pos); 806 snd_pcm_sframes_t nread; 807 808 nread = snd_pcm_readi( 809 alsa->handle, dst, len / hw->info.bytes_per_frame); 810 811 if (nread <= 0) { 812 switch (nread) { 813 case 0: 814 trace_alsa_read_zero(len); 815 return pos; 816 817 case -EPIPE: 818 if (alsa_recover(alsa->handle)) { 819 alsa_logerr(nread, "Failed to read %zu frames\n", len); 820 return pos; 821 } 822 trace_alsa_xrun_in(); 823 continue; 824 825 case -EAGAIN: 826 return pos; 827 828 default: 829 alsa_logerr(nread, "Failed to read %zu frames to %p\n", 830 len, dst); 831 return pos; 832 } 833 } 834 835 pos += nread * hw->info.bytes_per_frame; 836 len -= nread * hw->info.bytes_per_frame; 837 } 838 839 return pos; 840} 841 842static void alsa_enable_in(HWVoiceIn *hw, bool enable) 843{ 844 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; 845 AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in; 846 847 if (enable) { 848 bool poll_mode = apdo->try_poll; 849 850 ldebug("enabling voice\n"); 851 if (poll_mode && alsa_poll_in(hw)) { 852 poll_mode = 0; 853 } 854 hw->poll_mode = poll_mode; 855 856 alsa_voice_ctl(alsa->handle, "capture", VOICE_CTL_START); 857 } else { 858 ldebug ("disabling voice\n"); 859 if (hw->poll_mode) { 860 hw->poll_mode = 0; 861 alsa_fini_poll(&alsa->pollhlp); 862 } 863 alsa_voice_ctl(alsa->handle, "capture", VOICE_CTL_PAUSE); 864 } 865} 866 867static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo) 868{ 869 if (!apdo->has_try_poll) { 870 apdo->try_poll = true; 871 apdo->has_try_poll = true; 872 } 873} 874 875static void *alsa_audio_init(Audiodev *dev) 876{ 877 AudiodevAlsaOptions *aopts; 878 assert(dev->driver == AUDIODEV_DRIVER_ALSA); 879 880 aopts = &dev->u.alsa; 881 alsa_init_per_direction(aopts->in); 882 alsa_init_per_direction(aopts->out); 883 884 /* 885 * need to define them, as otherwise alsa produces no sound 886 * doesn't set has_* so alsa_open can identify it wasn't set by the user 887 */ 888 if (!dev->u.alsa.out->has_period_length) { 889 /* 1024 frames assuming 44100Hz */ 890 dev->u.alsa.out->period_length = 1024 * 1000000 / 44100; 891 } 892 if (!dev->u.alsa.out->has_buffer_length) { 893 /* 4096 frames assuming 44100Hz */ 894 dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100; 895 } 896 897 /* 898 * OptsVisitor sets unspecified optional fields to zero, but do not depend 899 * on it... 900 */ 901 if (!dev->u.alsa.in->has_period_length) { 902 dev->u.alsa.in->period_length = 0; 903 } 904 if (!dev->u.alsa.in->has_buffer_length) { 905 dev->u.alsa.in->buffer_length = 0; 906 } 907 908 return dev; 909} 910 911static void alsa_audio_fini (void *opaque) 912{ 913} 914 915static struct audio_pcm_ops alsa_pcm_ops = { 916 .init_out = alsa_init_out, 917 .fini_out = alsa_fini_out, 918 .write = alsa_write, 919 .run_buffer_out = audio_generic_run_buffer_out, 920 .enable_out = alsa_enable_out, 921 922 .init_in = alsa_init_in, 923 .fini_in = alsa_fini_in, 924 .read = alsa_read, 925 .run_buffer_in = audio_generic_run_buffer_in, 926 .enable_in = alsa_enable_in, 927}; 928 929static struct audio_driver alsa_audio_driver = { 930 .name = "alsa", 931 .descr = "ALSA http://www.alsa-project.org", 932 .init = alsa_audio_init, 933 .fini = alsa_audio_fini, 934 .pcm_ops = &alsa_pcm_ops, 935 .can_be_default = 1, 936 .max_voices_out = INT_MAX, 937 .max_voices_in = INT_MAX, 938 .voice_size_out = sizeof (ALSAVoiceOut), 939 .voice_size_in = sizeof (ALSAVoiceIn) 940}; 941 942static void register_audio_alsa(void) 943{ 944 audio_driver_register(&alsa_audio_driver); 945} 946type_init(register_audio_alsa);