block/qcow2: refactor encryption code
[qemu/ar7.git] / audio / alsaaudio.c
blob591344dccd1f986d5f3e1f37762369ffcdd534d4
1 /*
2 * QEMU ALSA audio driver
4 * Copyright (c) 2005 Vassili Karpov (malc)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
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"
32 #pragma GCC diagnostic ignored "-Waddress"
34 #define AUDIO_CAP "alsa"
35 #include "audio_int.h"
37 struct pollhlp {
38 snd_pcm_t *handle;
39 struct pollfd *pfds;
40 int count;
41 int mask;
42 AudioState *s;
45 typedef struct ALSAVoiceOut {
46 HWVoiceOut hw;
47 int wpos;
48 int pending;
49 void *pcm_buf;
50 snd_pcm_t *handle;
51 struct pollhlp pollhlp;
52 Audiodev *dev;
53 } ALSAVoiceOut;
55 typedef struct ALSAVoiceIn {
56 HWVoiceIn hw;
57 snd_pcm_t *handle;
58 void *pcm_buf;
59 struct pollhlp pollhlp;
60 Audiodev *dev;
61 } ALSAVoiceIn;
63 struct alsa_params_req {
64 int freq;
65 snd_pcm_format_t fmt;
66 int nchannels;
69 struct alsa_params_obt {
70 int freq;
71 AudioFormat fmt;
72 int endianness;
73 int nchannels;
74 snd_pcm_uframes_t samples;
77 static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
79 va_list ap;
81 va_start (ap, fmt);
82 AUD_vlog (AUDIO_CAP, fmt, ap);
83 va_end (ap);
85 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
88 static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
89 int err,
90 const char *typ,
91 const char *fmt,
92 ...
95 va_list ap;
97 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
99 va_start (ap, fmt);
100 AUD_vlog (AUDIO_CAP, fmt, ap);
101 va_end (ap);
103 AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
106 static void alsa_fini_poll (struct pollhlp *hlp)
108 int i;
109 struct pollfd *pfds = hlp->pfds;
111 if (pfds) {
112 for (i = 0; i < hlp->count; ++i) {
113 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
115 g_free (pfds);
117 hlp->pfds = NULL;
118 hlp->count = 0;
119 hlp->handle = NULL;
122 static void alsa_anal_close1 (snd_pcm_t **handlep)
124 int err = snd_pcm_close (*handlep);
125 if (err) {
126 alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
128 *handlep = NULL;
131 static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
133 alsa_fini_poll (hlp);
134 alsa_anal_close1 (handlep);
137 static int alsa_recover (snd_pcm_t *handle)
139 int err = snd_pcm_prepare (handle);
140 if (err < 0) {
141 alsa_logerr (err, "Failed to prepare handle %p\n", handle);
142 return -1;
144 return 0;
147 static int alsa_resume (snd_pcm_t *handle)
149 int err = snd_pcm_resume (handle);
150 if (err < 0) {
151 alsa_logerr (err, "Failed to resume handle %p\n", handle);
152 return -1;
154 return 0;
157 static void alsa_poll_handler (void *opaque)
159 int err, count;
160 snd_pcm_state_t state;
161 struct pollhlp *hlp = opaque;
162 unsigned short revents;
164 count = poll (hlp->pfds, hlp->count, 0);
165 if (count < 0) {
166 dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
167 return;
170 if (!count) {
171 return;
174 /* XXX: ALSA example uses initial count, not the one returned by
175 poll, correct? */
176 err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
177 hlp->count, &revents);
178 if (err < 0) {
179 alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
180 return;
183 if (!(revents & hlp->mask)) {
184 trace_alsa_revents(revents);
185 return;
188 state = snd_pcm_state (hlp->handle);
189 switch (state) {
190 case SND_PCM_STATE_SETUP:
191 alsa_recover (hlp->handle);
192 break;
194 case SND_PCM_STATE_XRUN:
195 alsa_recover (hlp->handle);
196 break;
198 case SND_PCM_STATE_SUSPENDED:
199 alsa_resume (hlp->handle);
200 break;
202 case SND_PCM_STATE_PREPARED:
203 audio_run(hlp->s, "alsa run (prepared)");
204 break;
206 case SND_PCM_STATE_RUNNING:
207 audio_run(hlp->s, "alsa run (running)");
208 break;
210 default:
211 dolog ("Unexpected state %d\n", state);
215 static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
217 int i, count, err;
218 struct pollfd *pfds;
220 count = snd_pcm_poll_descriptors_count (handle);
221 if (count <= 0) {
222 dolog ("Could not initialize poll mode\n"
223 "Invalid number of poll descriptors %d\n", count);
224 return -1;
227 pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
228 if (!pfds) {
229 dolog ("Could not initialize poll mode\n");
230 return -1;
233 err = snd_pcm_poll_descriptors (handle, pfds, count);
234 if (err < 0) {
235 alsa_logerr (err, "Could not initialize poll mode\n"
236 "Could not obtain poll descriptors\n");
237 g_free (pfds);
238 return -1;
241 for (i = 0; i < count; ++i) {
242 if (pfds[i].events & POLLIN) {
243 qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp);
245 if (pfds[i].events & POLLOUT) {
246 trace_alsa_pollout(i, pfds[i].fd);
247 qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp);
249 trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err);
252 hlp->pfds = pfds;
253 hlp->count = count;
254 hlp->handle = handle;
255 hlp->mask = mask;
256 return 0;
259 static int alsa_poll_out (HWVoiceOut *hw)
261 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
263 return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
266 static int alsa_poll_in (HWVoiceIn *hw)
268 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
270 return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
273 static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
275 switch (fmt) {
276 case AUDIO_FORMAT_S8:
277 return SND_PCM_FORMAT_S8;
279 case AUDIO_FORMAT_U8:
280 return SND_PCM_FORMAT_U8;
282 case AUDIO_FORMAT_S16:
283 if (endianness) {
284 return SND_PCM_FORMAT_S16_BE;
286 else {
287 return SND_PCM_FORMAT_S16_LE;
290 case AUDIO_FORMAT_U16:
291 if (endianness) {
292 return SND_PCM_FORMAT_U16_BE;
294 else {
295 return SND_PCM_FORMAT_U16_LE;
298 case AUDIO_FORMAT_S32:
299 if (endianness) {
300 return SND_PCM_FORMAT_S32_BE;
302 else {
303 return SND_PCM_FORMAT_S32_LE;
306 case AUDIO_FORMAT_U32:
307 if (endianness) {
308 return SND_PCM_FORMAT_U32_BE;
310 else {
311 return SND_PCM_FORMAT_U32_LE;
314 default:
315 dolog ("Internal logic error: Bad audio format %d\n", fmt);
316 #ifdef DEBUG_AUDIO
317 abort ();
318 #endif
319 return SND_PCM_FORMAT_U8;
323 static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
324 int *endianness)
326 switch (alsafmt) {
327 case SND_PCM_FORMAT_S8:
328 *endianness = 0;
329 *fmt = AUDIO_FORMAT_S8;
330 break;
332 case SND_PCM_FORMAT_U8:
333 *endianness = 0;
334 *fmt = AUDIO_FORMAT_U8;
335 break;
337 case SND_PCM_FORMAT_S16_LE:
338 *endianness = 0;
339 *fmt = AUDIO_FORMAT_S16;
340 break;
342 case SND_PCM_FORMAT_U16_LE:
343 *endianness = 0;
344 *fmt = AUDIO_FORMAT_U16;
345 break;
347 case SND_PCM_FORMAT_S16_BE:
348 *endianness = 1;
349 *fmt = AUDIO_FORMAT_S16;
350 break;
352 case SND_PCM_FORMAT_U16_BE:
353 *endianness = 1;
354 *fmt = AUDIO_FORMAT_U16;
355 break;
357 case SND_PCM_FORMAT_S32_LE:
358 *endianness = 0;
359 *fmt = AUDIO_FORMAT_S32;
360 break;
362 case SND_PCM_FORMAT_U32_LE:
363 *endianness = 0;
364 *fmt = AUDIO_FORMAT_U32;
365 break;
367 case SND_PCM_FORMAT_S32_BE:
368 *endianness = 1;
369 *fmt = AUDIO_FORMAT_S32;
370 break;
372 case SND_PCM_FORMAT_U32_BE:
373 *endianness = 1;
374 *fmt = AUDIO_FORMAT_U32;
375 break;
377 default:
378 dolog ("Unrecognized audio format %d\n", alsafmt);
379 return -1;
382 return 0;
385 static void alsa_dump_info (struct alsa_params_req *req,
386 struct alsa_params_obt *obt,
387 snd_pcm_format_t obtfmt,
388 AudiodevAlsaPerDirectionOptions *apdo)
390 dolog("parameter | requested value | obtained value\n");
391 dolog("format | %10d | %10d\n", req->fmt, obtfmt);
392 dolog("channels | %10d | %10d\n",
393 req->nchannels, obt->nchannels);
394 dolog("frequency | %10d | %10d\n", req->freq, obt->freq);
395 dolog("============================================\n");
396 dolog("requested: buffer len %" PRId32 " period len %" PRId32 "\n",
397 apdo->buffer_length, apdo->period_length);
398 dolog("obtained: samples %ld\n", obt->samples);
401 static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
403 int err;
404 snd_pcm_sw_params_t *sw_params;
406 snd_pcm_sw_params_alloca (&sw_params);
408 err = snd_pcm_sw_params_current (handle, sw_params);
409 if (err < 0) {
410 dolog ("Could not fully initialize DAC\n");
411 alsa_logerr (err, "Failed to get current software parameters\n");
412 return;
415 err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
416 if (err < 0) {
417 dolog ("Could not fully initialize DAC\n");
418 alsa_logerr (err, "Failed to set software threshold to %ld\n",
419 threshold);
420 return;
423 err = snd_pcm_sw_params (handle, sw_params);
424 if (err < 0) {
425 dolog ("Could not fully initialize DAC\n");
426 alsa_logerr (err, "Failed to set software parameters\n");
427 return;
431 static int alsa_open(bool in, struct alsa_params_req *req,
432 struct alsa_params_obt *obt, snd_pcm_t **handlep,
433 Audiodev *dev)
435 AudiodevAlsaOptions *aopts = &dev->u.alsa;
436 AudiodevAlsaPerDirectionOptions *apdo = in ? aopts->in : aopts->out;
437 snd_pcm_t *handle;
438 snd_pcm_hw_params_t *hw_params;
439 int err;
440 unsigned int freq, nchannels;
441 const char *pcm_name = apdo->has_dev ? apdo->dev : "default";
442 snd_pcm_uframes_t obt_buffer_size;
443 const char *typ = in ? "ADC" : "DAC";
444 snd_pcm_format_t obtfmt;
446 freq = req->freq;
447 nchannels = req->nchannels;
449 snd_pcm_hw_params_alloca (&hw_params);
451 err = snd_pcm_open (
452 &handle,
453 pcm_name,
454 in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
455 SND_PCM_NONBLOCK
457 if (err < 0) {
458 alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
459 return -1;
462 err = snd_pcm_hw_params_any (handle, hw_params);
463 if (err < 0) {
464 alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
465 goto err;
468 err = snd_pcm_hw_params_set_access (
469 handle,
470 hw_params,
471 SND_PCM_ACCESS_RW_INTERLEAVED
473 if (err < 0) {
474 alsa_logerr2 (err, typ, "Failed to set access type\n");
475 goto err;
478 err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
479 if (err < 0) {
480 alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
483 err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
484 if (err < 0) {
485 alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
486 goto err;
489 err = snd_pcm_hw_params_set_channels_near (
490 handle,
491 hw_params,
492 &nchannels
494 if (err < 0) {
495 alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
496 req->nchannels);
497 goto err;
500 if (nchannels != 1 && nchannels != 2) {
501 alsa_logerr2 (err, typ,
502 "Can not handle obtained number of channels %d\n",
503 nchannels);
504 goto err;
507 if (apdo->buffer_length) {
508 int dir = 0;
509 unsigned int btime = apdo->buffer_length;
511 err = snd_pcm_hw_params_set_buffer_time_near(
512 handle, hw_params, &btime, &dir);
514 if (err < 0) {
515 alsa_logerr2(err, typ, "Failed to set buffer time to %" PRId32 "\n",
516 apdo->buffer_length);
517 goto err;
520 if (apdo->has_buffer_length && btime != apdo->buffer_length) {
521 dolog("Requested buffer time %" PRId32
522 " was rejected, using %u\n", apdo->buffer_length, btime);
526 if (apdo->period_length) {
527 int dir = 0;
528 unsigned int ptime = apdo->period_length;
530 err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &ptime,
531 &dir);
533 if (err < 0) {
534 alsa_logerr2(err, typ, "Failed to set period time to %" PRId32 "\n",
535 apdo->period_length);
536 goto err;
539 if (apdo->has_period_length && ptime != apdo->period_length) {
540 dolog("Requested period time %" PRId32 " was rejected, using %d\n",
541 apdo->period_length, ptime);
545 err = snd_pcm_hw_params (handle, hw_params);
546 if (err < 0) {
547 alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
548 goto err;
551 err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
552 if (err < 0) {
553 alsa_logerr2 (err, typ, "Failed to get buffer size\n");
554 goto err;
557 err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
558 if (err < 0) {
559 alsa_logerr2 (err, typ, "Failed to get format\n");
560 goto err;
563 if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
564 dolog ("Invalid format was returned %d\n", obtfmt);
565 goto err;
568 err = snd_pcm_prepare (handle);
569 if (err < 0) {
570 alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
571 goto err;
574 if (!in && aopts->has_threshold && aopts->threshold) {
575 struct audsettings as = { .freq = freq };
576 alsa_set_threshold(
577 handle,
578 audio_buffer_frames(qapi_AudiodevAlsaPerDirectionOptions_base(apdo),
579 &as, aopts->threshold));
582 obt->nchannels = nchannels;
583 obt->freq = freq;
584 obt->samples = obt_buffer_size;
586 *handlep = handle;
588 if (obtfmt != req->fmt ||
589 obt->nchannels != req->nchannels ||
590 obt->freq != req->freq) {
591 dolog ("Audio parameters for %s\n", typ);
592 alsa_dump_info(req, obt, obtfmt, apdo);
595 #ifdef DEBUG
596 alsa_dump_info(req, obt, obtfmt, pdo);
597 #endif
598 return 0;
600 err:
601 alsa_anal_close1 (&handle);
602 return -1;
605 static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
607 snd_pcm_sframes_t avail;
609 avail = snd_pcm_avail_update (handle);
610 if (avail < 0) {
611 if (avail == -EPIPE) {
612 if (!alsa_recover (handle)) {
613 avail = snd_pcm_avail_update (handle);
617 if (avail < 0) {
618 alsa_logerr (avail,
619 "Could not obtain number of available frames\n");
620 return -1;
624 return avail;
627 static void alsa_write_pending (ALSAVoiceOut *alsa)
629 HWVoiceOut *hw = &alsa->hw;
631 while (alsa->pending) {
632 int left_till_end_samples = hw->samples - alsa->wpos;
633 int len = MIN (alsa->pending, left_till_end_samples);
634 char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
636 while (len) {
637 snd_pcm_sframes_t written;
639 written = snd_pcm_writei (alsa->handle, src, len);
641 if (written <= 0) {
642 switch (written) {
643 case 0:
644 trace_alsa_wrote_zero(len);
645 return;
647 case -EPIPE:
648 if (alsa_recover (alsa->handle)) {
649 alsa_logerr (written, "Failed to write %d frames\n",
650 len);
651 return;
653 trace_alsa_xrun_out();
654 continue;
656 case -ESTRPIPE:
657 /* stream is suspended and waiting for an
658 application recovery */
659 if (alsa_resume (alsa->handle)) {
660 alsa_logerr (written, "Failed to write %d frames\n",
661 len);
662 return;
664 trace_alsa_resume_out();
665 continue;
667 case -EAGAIN:
668 return;
670 default:
671 alsa_logerr (written, "Failed to write %d frames from %p\n",
672 len, src);
673 return;
677 alsa->wpos = (alsa->wpos + written) % hw->samples;
678 alsa->pending -= written;
679 len -= written;
684 static size_t alsa_run_out(HWVoiceOut *hw, size_t live)
686 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
687 size_t decr;
688 snd_pcm_sframes_t avail;
690 avail = alsa_get_avail (alsa->handle);
691 if (avail < 0) {
692 dolog ("Could not get number of available playback frames\n");
693 return 0;
696 decr = MIN (live, avail);
697 decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
698 alsa->pending += decr;
699 alsa_write_pending (alsa);
700 return decr;
703 static void alsa_fini_out (HWVoiceOut *hw)
705 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
707 ldebug ("alsa_fini\n");
708 alsa_anal_close (&alsa->handle, &alsa->pollhlp);
710 g_free(alsa->pcm_buf);
711 alsa->pcm_buf = NULL;
714 static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
715 void *drv_opaque)
717 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
718 struct alsa_params_req req;
719 struct alsa_params_obt obt;
720 snd_pcm_t *handle;
721 struct audsettings obt_as;
722 Audiodev *dev = drv_opaque;
724 req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
725 req.freq = as->freq;
726 req.nchannels = as->nchannels;
728 if (alsa_open(0, &req, &obt, &handle, dev)) {
729 return -1;
732 obt_as.freq = obt.freq;
733 obt_as.nchannels = obt.nchannels;
734 obt_as.fmt = obt.fmt;
735 obt_as.endianness = obt.endianness;
737 audio_pcm_init_info (&hw->info, &obt_as);
738 hw->samples = obt.samples;
740 alsa->pcm_buf = audio_calloc(__func__, obt.samples, 1 << hw->info.shift);
741 if (!alsa->pcm_buf) {
742 dolog("Could not allocate DAC buffer (%zu samples, each %d bytes)\n",
743 hw->samples, 1 << hw->info.shift);
744 alsa_anal_close1 (&handle);
745 return -1;
748 alsa->pollhlp.s = hw->s;
749 alsa->handle = handle;
750 alsa->dev = dev;
751 return 0;
754 #define VOICE_CTL_PAUSE 0
755 #define VOICE_CTL_PREPARE 1
756 #define VOICE_CTL_START 2
758 static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
760 int err;
762 if (ctl == VOICE_CTL_PAUSE) {
763 err = snd_pcm_drop (handle);
764 if (err < 0) {
765 alsa_logerr (err, "Could not stop %s\n", typ);
766 return -1;
769 else {
770 err = snd_pcm_prepare (handle);
771 if (err < 0) {
772 alsa_logerr (err, "Could not prepare handle for %s\n", typ);
773 return -1;
775 if (ctl == VOICE_CTL_START) {
776 err = snd_pcm_start(handle);
777 if (err < 0) {
778 alsa_logerr (err, "Could not start handle for %s\n", typ);
779 return -1;
784 return 0;
787 static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
789 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
790 AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out;
792 switch (cmd) {
793 case VOICE_ENABLE:
795 bool poll_mode = apdo->try_poll;
797 ldebug ("enabling voice\n");
798 if (poll_mode && alsa_poll_out (hw)) {
799 poll_mode = 0;
801 hw->poll_mode = poll_mode;
802 return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
805 case VOICE_DISABLE:
806 ldebug ("disabling voice\n");
807 if (hw->poll_mode) {
808 hw->poll_mode = 0;
809 alsa_fini_poll (&alsa->pollhlp);
811 return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
814 return -1;
817 static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
819 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
820 struct alsa_params_req req;
821 struct alsa_params_obt obt;
822 snd_pcm_t *handle;
823 struct audsettings obt_as;
824 Audiodev *dev = drv_opaque;
826 req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
827 req.freq = as->freq;
828 req.nchannels = as->nchannels;
830 if (alsa_open(1, &req, &obt, &handle, dev)) {
831 return -1;
834 obt_as.freq = obt.freq;
835 obt_as.nchannels = obt.nchannels;
836 obt_as.fmt = obt.fmt;
837 obt_as.endianness = obt.endianness;
839 audio_pcm_init_info (&hw->info, &obt_as);
840 hw->samples = obt.samples;
842 alsa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
843 if (!alsa->pcm_buf) {
844 dolog("Could not allocate ADC buffer (%zu samples, each %d bytes)\n",
845 hw->samples, 1 << hw->info.shift);
846 alsa_anal_close1 (&handle);
847 return -1;
850 alsa->pollhlp.s = hw->s;
851 alsa->handle = handle;
852 alsa->dev = dev;
853 return 0;
856 static void alsa_fini_in (HWVoiceIn *hw)
858 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
860 alsa_anal_close (&alsa->handle, &alsa->pollhlp);
862 g_free(alsa->pcm_buf);
863 alsa->pcm_buf = NULL;
866 static size_t alsa_run_in(HWVoiceIn *hw)
868 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
869 int hwshift = hw->info.shift;
870 int i;
871 size_t live = audio_pcm_hw_get_live_in (hw);
872 size_t dead = hw->samples - live;
873 size_t decr;
874 struct {
875 size_t add;
876 size_t len;
877 } bufs[2] = {
878 { .add = hw->wpos, .len = 0 },
879 { .add = 0, .len = 0 }
881 snd_pcm_sframes_t avail;
882 snd_pcm_uframes_t read_samples = 0;
884 if (!dead) {
885 return 0;
888 avail = alsa_get_avail (alsa->handle);
889 if (avail < 0) {
890 dolog ("Could not get number of captured frames\n");
891 return 0;
894 if (!avail) {
895 snd_pcm_state_t state;
897 state = snd_pcm_state (alsa->handle);
898 switch (state) {
899 case SND_PCM_STATE_PREPARED:
900 avail = hw->samples;
901 break;
902 case SND_PCM_STATE_SUSPENDED:
903 /* stream is suspended and waiting for an application recovery */
904 if (alsa_resume (alsa->handle)) {
905 dolog ("Failed to resume suspended input stream\n");
906 return 0;
908 trace_alsa_resume_in();
909 break;
910 default:
911 trace_alsa_no_frames(state);
912 return 0;
916 decr = MIN(dead, avail);
917 if (!decr) {
918 return 0;
921 if (hw->wpos + decr > hw->samples) {
922 bufs[0].len = (hw->samples - hw->wpos);
923 bufs[1].len = (decr - (hw->samples - hw->wpos));
925 else {
926 bufs[0].len = decr;
929 for (i = 0; i < 2; ++i) {
930 void *src;
931 struct st_sample *dst;
932 snd_pcm_sframes_t nread;
933 snd_pcm_uframes_t len;
935 len = bufs[i].len;
937 src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
938 dst = hw->conv_buf + bufs[i].add;
940 while (len) {
941 nread = snd_pcm_readi (alsa->handle, src, len);
943 if (nread <= 0) {
944 switch (nread) {
945 case 0:
946 trace_alsa_read_zero(len);
947 goto exit;
949 case -EPIPE:
950 if (alsa_recover (alsa->handle)) {
951 alsa_logerr (nread, "Failed to read %ld frames\n", len);
952 goto exit;
954 trace_alsa_xrun_in();
955 continue;
957 case -EAGAIN:
958 goto exit;
960 default:
961 alsa_logerr (
962 nread,
963 "Failed to read %ld frames from %p\n",
964 len,
967 goto exit;
971 hw->conv (dst, src, nread);
973 src = advance (src, nread << hwshift);
974 dst += nread;
976 read_samples += nread;
977 len -= nread;
981 exit:
982 hw->wpos = (hw->wpos + read_samples) % hw->samples;
983 return read_samples;
986 static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
988 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
989 AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in;
991 switch (cmd) {
992 case VOICE_ENABLE:
994 bool poll_mode = apdo->try_poll;
996 ldebug ("enabling voice\n");
997 if (poll_mode && alsa_poll_in (hw)) {
998 poll_mode = 0;
1000 hw->poll_mode = poll_mode;
1002 return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
1005 case VOICE_DISABLE:
1006 ldebug ("disabling voice\n");
1007 if (hw->poll_mode) {
1008 hw->poll_mode = 0;
1009 alsa_fini_poll (&alsa->pollhlp);
1011 return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
1014 return -1;
1017 static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo)
1019 if (!apdo->has_try_poll) {
1020 apdo->try_poll = true;
1021 apdo->has_try_poll = true;
1025 static void *alsa_audio_init(Audiodev *dev)
1027 AudiodevAlsaOptions *aopts;
1028 assert(dev->driver == AUDIODEV_DRIVER_ALSA);
1030 aopts = &dev->u.alsa;
1031 alsa_init_per_direction(aopts->in);
1032 alsa_init_per_direction(aopts->out);
1035 * need to define them, as otherwise alsa produces no sound
1036 * doesn't set has_* so alsa_open can identify it wasn't set by the user
1038 if (!dev->u.alsa.out->has_period_length) {
1039 /* 1024 frames assuming 44100Hz */
1040 dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
1042 if (!dev->u.alsa.out->has_buffer_length) {
1043 /* 4096 frames assuming 44100Hz */
1044 dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100;
1048 * OptsVisitor sets unspecified optional fields to zero, but do not depend
1049 * on it...
1051 if (!dev->u.alsa.in->has_period_length) {
1052 dev->u.alsa.in->period_length = 0;
1054 if (!dev->u.alsa.in->has_buffer_length) {
1055 dev->u.alsa.in->buffer_length = 0;
1058 return dev;
1061 static void alsa_audio_fini (void *opaque)
1065 static struct audio_pcm_ops alsa_pcm_ops = {
1066 .init_out = alsa_init_out,
1067 .fini_out = alsa_fini_out,
1068 .run_out = alsa_run_out,
1069 .ctl_out = alsa_ctl_out,
1071 .init_in = alsa_init_in,
1072 .fini_in = alsa_fini_in,
1073 .run_in = alsa_run_in,
1074 .ctl_in = alsa_ctl_in,
1077 static struct audio_driver alsa_audio_driver = {
1078 .name = "alsa",
1079 .descr = "ALSA http://www.alsa-project.org",
1080 .init = alsa_audio_init,
1081 .fini = alsa_audio_fini,
1082 .pcm_ops = &alsa_pcm_ops,
1083 .can_be_default = 1,
1084 .max_voices_out = INT_MAX,
1085 .max_voices_in = INT_MAX,
1086 .voice_size_out = sizeof (ALSAVoiceOut),
1087 .voice_size_in = sizeof (ALSAVoiceIn)
1090 static void register_audio_alsa(void)
1092 audio_driver_register(&alsa_audio_driver);
1094 type_init(register_audio_alsa);