xref: /openbmc/qemu/audio/alsaaudio.c (revision b45c03f5)
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 #include <alsa/asoundlib.h>
25 #include "qemu-common.h"
26 #include "qemu/main-loop.h"
27 #include "audio.h"
28 #include "trace.h"
29 
30 #if QEMU_GNUC_PREREQ(4, 3)
31 #pragma GCC diagnostic ignored "-Waddress"
32 #endif
33 
34 #define AUDIO_CAP "alsa"
35 #include "audio_int.h"
36 
37 typedef struct ALSAConf {
38     int size_in_usec_in;
39     int size_in_usec_out;
40     const char *pcm_name_in;
41     const char *pcm_name_out;
42     unsigned int buffer_size_in;
43     unsigned int period_size_in;
44     unsigned int buffer_size_out;
45     unsigned int period_size_out;
46     unsigned int threshold;
47 
48     int buffer_size_in_overridden;
49     int period_size_in_overridden;
50 
51     int buffer_size_out_overridden;
52     int period_size_out_overridden;
53 } ALSAConf;
54 
55 struct pollhlp {
56     snd_pcm_t *handle;
57     struct pollfd *pfds;
58     ALSAConf *conf;
59     int count;
60     int mask;
61 };
62 
63 typedef struct ALSAVoiceOut {
64     HWVoiceOut hw;
65     int wpos;
66     int pending;
67     void *pcm_buf;
68     snd_pcm_t *handle;
69     struct pollhlp pollhlp;
70 } ALSAVoiceOut;
71 
72 typedef struct ALSAVoiceIn {
73     HWVoiceIn hw;
74     snd_pcm_t *handle;
75     void *pcm_buf;
76     struct pollhlp pollhlp;
77 } ALSAVoiceIn;
78 
79 struct alsa_params_req {
80     int freq;
81     snd_pcm_format_t fmt;
82     int nchannels;
83     int size_in_usec;
84     int override_mask;
85     unsigned int buffer_size;
86     unsigned int period_size;
87 };
88 
89 struct alsa_params_obt {
90     int freq;
91     audfmt_e fmt;
92     int endianness;
93     int nchannels;
94     snd_pcm_uframes_t samples;
95 };
96 
97 static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
98 {
99     va_list ap;
100 
101     va_start (ap, fmt);
102     AUD_vlog (AUDIO_CAP, fmt, ap);
103     va_end (ap);
104 
105     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
106 }
107 
108 static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
109     int err,
110     const char *typ,
111     const char *fmt,
112     ...
113     )
114 {
115     va_list ap;
116 
117     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
118 
119     va_start (ap, fmt);
120     AUD_vlog (AUDIO_CAP, fmt, ap);
121     va_end (ap);
122 
123     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
124 }
125 
126 static void alsa_fini_poll (struct pollhlp *hlp)
127 {
128     int i;
129     struct pollfd *pfds = hlp->pfds;
130 
131     if (pfds) {
132         for (i = 0; i < hlp->count; ++i) {
133             qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
134         }
135         g_free (pfds);
136     }
137     hlp->pfds = NULL;
138     hlp->count = 0;
139     hlp->handle = NULL;
140 }
141 
142 static void alsa_anal_close1 (snd_pcm_t **handlep)
143 {
144     int err = snd_pcm_close (*handlep);
145     if (err) {
146         alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
147     }
148     *handlep = NULL;
149 }
150 
151 static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
152 {
153     alsa_fini_poll (hlp);
154     alsa_anal_close1 (handlep);
155 }
156 
157 static int alsa_recover (snd_pcm_t *handle)
158 {
159     int err = snd_pcm_prepare (handle);
160     if (err < 0) {
161         alsa_logerr (err, "Failed to prepare handle %p\n", handle);
162         return -1;
163     }
164     return 0;
165 }
166 
167 static int alsa_resume (snd_pcm_t *handle)
168 {
169     int err = snd_pcm_resume (handle);
170     if (err < 0) {
171         alsa_logerr (err, "Failed to resume handle %p\n", handle);
172         return -1;
173     }
174     return 0;
175 }
176 
177 static void alsa_poll_handler (void *opaque)
178 {
179     int err, count;
180     snd_pcm_state_t state;
181     struct pollhlp *hlp = opaque;
182     unsigned short revents;
183 
184     count = poll (hlp->pfds, hlp->count, 0);
185     if (count < 0) {
186         dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
187         return;
188     }
189 
190     if (!count) {
191         return;
192     }
193 
194     /* XXX: ALSA example uses initial count, not the one returned by
195        poll, correct? */
196     err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
197                                             hlp->count, &revents);
198     if (err < 0) {
199         alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
200         return;
201     }
202 
203     if (!(revents & hlp->mask)) {
204         trace_alsa_revents(revents);
205         return;
206     }
207 
208     state = snd_pcm_state (hlp->handle);
209     switch (state) {
210     case SND_PCM_STATE_SETUP:
211         alsa_recover (hlp->handle);
212         break;
213 
214     case SND_PCM_STATE_XRUN:
215         alsa_recover (hlp->handle);
216         break;
217 
218     case SND_PCM_STATE_SUSPENDED:
219         alsa_resume (hlp->handle);
220         break;
221 
222     case SND_PCM_STATE_PREPARED:
223         audio_run ("alsa run (prepared)");
224         break;
225 
226     case SND_PCM_STATE_RUNNING:
227         audio_run ("alsa run (running)");
228         break;
229 
230     default:
231         dolog ("Unexpected state %d\n", state);
232     }
233 }
234 
235 static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
236 {
237     int i, count, err;
238     struct pollfd *pfds;
239 
240     count = snd_pcm_poll_descriptors_count (handle);
241     if (count <= 0) {
242         dolog ("Could not initialize poll mode\n"
243                "Invalid number of poll descriptors %d\n", count);
244         return -1;
245     }
246 
247     pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
248     if (!pfds) {
249         dolog ("Could not initialize poll mode\n");
250         return -1;
251     }
252 
253     err = snd_pcm_poll_descriptors (handle, pfds, count);
254     if (err < 0) {
255         alsa_logerr (err, "Could not initialize poll mode\n"
256                      "Could not obtain poll descriptors\n");
257         g_free (pfds);
258         return -1;
259     }
260 
261     for (i = 0; i < count; ++i) {
262         if (pfds[i].events & POLLIN) {
263             qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp);
264         }
265         if (pfds[i].events & POLLOUT) {
266             trace_alsa_pollout(i, pfds[i].fd);
267             qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp);
268         }
269         trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err);
270 
271     }
272     hlp->pfds = pfds;
273     hlp->count = count;
274     hlp->handle = handle;
275     hlp->mask = mask;
276     return 0;
277 }
278 
279 static int alsa_poll_out (HWVoiceOut *hw)
280 {
281     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
282 
283     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
284 }
285 
286 static int alsa_poll_in (HWVoiceIn *hw)
287 {
288     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
289 
290     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
291 }
292 
293 static int alsa_write (SWVoiceOut *sw, void *buf, int len)
294 {
295     return audio_pcm_sw_write (sw, buf, len);
296 }
297 
298 static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
299 {
300     switch (fmt) {
301     case AUD_FMT_S8:
302         return SND_PCM_FORMAT_S8;
303 
304     case AUD_FMT_U8:
305         return SND_PCM_FORMAT_U8;
306 
307     case AUD_FMT_S16:
308         if (endianness) {
309             return SND_PCM_FORMAT_S16_BE;
310         }
311         else {
312             return SND_PCM_FORMAT_S16_LE;
313         }
314 
315     case AUD_FMT_U16:
316         if (endianness) {
317             return SND_PCM_FORMAT_U16_BE;
318         }
319         else {
320             return SND_PCM_FORMAT_U16_LE;
321         }
322 
323     case AUD_FMT_S32:
324         if (endianness) {
325             return SND_PCM_FORMAT_S32_BE;
326         }
327         else {
328             return SND_PCM_FORMAT_S32_LE;
329         }
330 
331     case AUD_FMT_U32:
332         if (endianness) {
333             return SND_PCM_FORMAT_U32_BE;
334         }
335         else {
336             return SND_PCM_FORMAT_U32_LE;
337         }
338 
339     default:
340         dolog ("Internal logic error: Bad audio format %d\n", fmt);
341 #ifdef DEBUG_AUDIO
342         abort ();
343 #endif
344         return SND_PCM_FORMAT_U8;
345     }
346 }
347 
348 static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
349                            int *endianness)
350 {
351     switch (alsafmt) {
352     case SND_PCM_FORMAT_S8:
353         *endianness = 0;
354         *fmt = AUD_FMT_S8;
355         break;
356 
357     case SND_PCM_FORMAT_U8:
358         *endianness = 0;
359         *fmt = AUD_FMT_U8;
360         break;
361 
362     case SND_PCM_FORMAT_S16_LE:
363         *endianness = 0;
364         *fmt = AUD_FMT_S16;
365         break;
366 
367     case SND_PCM_FORMAT_U16_LE:
368         *endianness = 0;
369         *fmt = AUD_FMT_U16;
370         break;
371 
372     case SND_PCM_FORMAT_S16_BE:
373         *endianness = 1;
374         *fmt = AUD_FMT_S16;
375         break;
376 
377     case SND_PCM_FORMAT_U16_BE:
378         *endianness = 1;
379         *fmt = AUD_FMT_U16;
380         break;
381 
382     case SND_PCM_FORMAT_S32_LE:
383         *endianness = 0;
384         *fmt = AUD_FMT_S32;
385         break;
386 
387     case SND_PCM_FORMAT_U32_LE:
388         *endianness = 0;
389         *fmt = AUD_FMT_U32;
390         break;
391 
392     case SND_PCM_FORMAT_S32_BE:
393         *endianness = 1;
394         *fmt = AUD_FMT_S32;
395         break;
396 
397     case SND_PCM_FORMAT_U32_BE:
398         *endianness = 1;
399         *fmt = AUD_FMT_U32;
400         break;
401 
402     default:
403         dolog ("Unrecognized audio format %d\n", alsafmt);
404         return -1;
405     }
406 
407     return 0;
408 }
409 
410 static void alsa_dump_info (struct alsa_params_req *req,
411                             struct alsa_params_obt *obt,
412                             snd_pcm_format_t obtfmt)
413 {
414     dolog ("parameter | requested value | obtained value\n");
415     dolog ("format    |      %10d |     %10d\n", req->fmt, obtfmt);
416     dolog ("channels  |      %10d |     %10d\n",
417            req->nchannels, obt->nchannels);
418     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
419     dolog ("============================================\n");
420     dolog ("requested: buffer size %d period size %d\n",
421            req->buffer_size, req->period_size);
422     dolog ("obtained: samples %ld\n", obt->samples);
423 }
424 
425 static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
426 {
427     int err;
428     snd_pcm_sw_params_t *sw_params;
429 
430     snd_pcm_sw_params_alloca (&sw_params);
431 
432     err = snd_pcm_sw_params_current (handle, sw_params);
433     if (err < 0) {
434         dolog ("Could not fully initialize DAC\n");
435         alsa_logerr (err, "Failed to get current software parameters\n");
436         return;
437     }
438 
439     err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
440     if (err < 0) {
441         dolog ("Could not fully initialize DAC\n");
442         alsa_logerr (err, "Failed to set software threshold to %ld\n",
443                      threshold);
444         return;
445     }
446 
447     err = snd_pcm_sw_params (handle, sw_params);
448     if (err < 0) {
449         dolog ("Could not fully initialize DAC\n");
450         alsa_logerr (err, "Failed to set software parameters\n");
451         return;
452     }
453 }
454 
455 static int alsa_open (int in, struct alsa_params_req *req,
456                       struct alsa_params_obt *obt, snd_pcm_t **handlep,
457                       ALSAConf *conf)
458 {
459     snd_pcm_t *handle;
460     snd_pcm_hw_params_t *hw_params;
461     int err;
462     int size_in_usec;
463     unsigned int freq, nchannels;
464     const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out;
465     snd_pcm_uframes_t obt_buffer_size;
466     const char *typ = in ? "ADC" : "DAC";
467     snd_pcm_format_t obtfmt;
468 
469     freq = req->freq;
470     nchannels = req->nchannels;
471     size_in_usec = req->size_in_usec;
472 
473     snd_pcm_hw_params_alloca (&hw_params);
474 
475     err = snd_pcm_open (
476         &handle,
477         pcm_name,
478         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
479         SND_PCM_NONBLOCK
480         );
481     if (err < 0) {
482         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
483         return -1;
484     }
485 
486     err = snd_pcm_hw_params_any (handle, hw_params);
487     if (err < 0) {
488         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
489         goto err;
490     }
491 
492     err = snd_pcm_hw_params_set_access (
493         handle,
494         hw_params,
495         SND_PCM_ACCESS_RW_INTERLEAVED
496         );
497     if (err < 0) {
498         alsa_logerr2 (err, typ, "Failed to set access type\n");
499         goto err;
500     }
501 
502     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
503     if (err < 0) {
504         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
505     }
506 
507     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
508     if (err < 0) {
509         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
510         goto err;
511     }
512 
513     err = snd_pcm_hw_params_set_channels_near (
514         handle,
515         hw_params,
516         &nchannels
517         );
518     if (err < 0) {
519         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
520                       req->nchannels);
521         goto err;
522     }
523 
524     if (nchannels != 1 && nchannels != 2) {
525         alsa_logerr2 (err, typ,
526                       "Can not handle obtained number of channels %d\n",
527                       nchannels);
528         goto err;
529     }
530 
531     if (req->buffer_size) {
532         unsigned long obt;
533 
534         if (size_in_usec) {
535             int dir = 0;
536             unsigned int btime = req->buffer_size;
537 
538             err = snd_pcm_hw_params_set_buffer_time_near (
539                 handle,
540                 hw_params,
541                 &btime,
542                 &dir
543                 );
544             obt = btime;
545         }
546         else {
547             snd_pcm_uframes_t bsize = req->buffer_size;
548 
549             err = snd_pcm_hw_params_set_buffer_size_near (
550                 handle,
551                 hw_params,
552                 &bsize
553                 );
554             obt = bsize;
555         }
556         if (err < 0) {
557             alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
558                           size_in_usec ? "time" : "size", req->buffer_size);
559             goto err;
560         }
561 
562         if ((req->override_mask & 2) && (obt - req->buffer_size))
563             dolog ("Requested buffer %s %u was rejected, using %lu\n",
564                    size_in_usec ? "time" : "size", req->buffer_size, obt);
565     }
566 
567     if (req->period_size) {
568         unsigned long obt;
569 
570         if (size_in_usec) {
571             int dir = 0;
572             unsigned int ptime = req->period_size;
573 
574             err = snd_pcm_hw_params_set_period_time_near (
575                 handle,
576                 hw_params,
577                 &ptime,
578                 &dir
579                 );
580             obt = ptime;
581         }
582         else {
583             int dir = 0;
584             snd_pcm_uframes_t psize = req->period_size;
585 
586             err = snd_pcm_hw_params_set_period_size_near (
587                 handle,
588                 hw_params,
589                 &psize,
590                 &dir
591                 );
592             obt = psize;
593         }
594 
595         if (err < 0) {
596             alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
597                           size_in_usec ? "time" : "size", req->period_size);
598             goto err;
599         }
600 
601         if (((req->override_mask & 1) && (obt - req->period_size)))
602             dolog ("Requested period %s %u was rejected, using %lu\n",
603                    size_in_usec ? "time" : "size", req->period_size, obt);
604     }
605 
606     err = snd_pcm_hw_params (handle, hw_params);
607     if (err < 0) {
608         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
609         goto err;
610     }
611 
612     err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
613     if (err < 0) {
614         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
615         goto err;
616     }
617 
618     err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
619     if (err < 0) {
620         alsa_logerr2 (err, typ, "Failed to get format\n");
621         goto err;
622     }
623 
624     if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
625         dolog ("Invalid format was returned %d\n", obtfmt);
626         goto err;
627     }
628 
629     err = snd_pcm_prepare (handle);
630     if (err < 0) {
631         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
632         goto err;
633     }
634 
635     if (!in && conf->threshold) {
636         snd_pcm_uframes_t threshold;
637         int bytes_per_sec;
638 
639         bytes_per_sec = freq << (nchannels == 2);
640 
641         switch (obt->fmt) {
642         case AUD_FMT_S8:
643         case AUD_FMT_U8:
644             break;
645 
646         case AUD_FMT_S16:
647         case AUD_FMT_U16:
648             bytes_per_sec <<= 1;
649             break;
650 
651         case AUD_FMT_S32:
652         case AUD_FMT_U32:
653             bytes_per_sec <<= 2;
654             break;
655         }
656 
657         threshold = (conf->threshold * bytes_per_sec) / 1000;
658         alsa_set_threshold (handle, threshold);
659     }
660 
661     obt->nchannels = nchannels;
662     obt->freq = freq;
663     obt->samples = obt_buffer_size;
664 
665     *handlep = handle;
666 
667     if (obtfmt != req->fmt ||
668          obt->nchannels != req->nchannels ||
669          obt->freq != req->freq) {
670         dolog ("Audio parameters for %s\n", typ);
671         alsa_dump_info (req, obt, obtfmt);
672     }
673 
674 #ifdef DEBUG
675     alsa_dump_info (req, obt, obtfmt);
676 #endif
677     return 0;
678 
679  err:
680     alsa_anal_close1 (&handle);
681     return -1;
682 }
683 
684 static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
685 {
686     snd_pcm_sframes_t avail;
687 
688     avail = snd_pcm_avail_update (handle);
689     if (avail < 0) {
690         if (avail == -EPIPE) {
691             if (!alsa_recover (handle)) {
692                 avail = snd_pcm_avail_update (handle);
693             }
694         }
695 
696         if (avail < 0) {
697             alsa_logerr (avail,
698                          "Could not obtain number of available frames\n");
699             return -1;
700         }
701     }
702 
703     return avail;
704 }
705 
706 static void alsa_write_pending (ALSAVoiceOut *alsa)
707 {
708     HWVoiceOut *hw = &alsa->hw;
709 
710     while (alsa->pending) {
711         int left_till_end_samples = hw->samples - alsa->wpos;
712         int len = audio_MIN (alsa->pending, left_till_end_samples);
713         char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
714 
715         while (len) {
716             snd_pcm_sframes_t written;
717 
718             written = snd_pcm_writei (alsa->handle, src, len);
719 
720             if (written <= 0) {
721                 switch (written) {
722                 case 0:
723                     trace_alsa_wrote_zero(len);
724                     return;
725 
726                 case -EPIPE:
727                     if (alsa_recover (alsa->handle)) {
728                         alsa_logerr (written, "Failed to write %d frames\n",
729                                      len);
730                         return;
731                     }
732                     trace_alsa_xrun_out();
733                     continue;
734 
735                 case -ESTRPIPE:
736                     /* stream is suspended and waiting for an
737                        application recovery */
738                     if (alsa_resume (alsa->handle)) {
739                         alsa_logerr (written, "Failed to write %d frames\n",
740                                      len);
741                         return;
742                     }
743                     trace_alsa_resume_out();
744                     continue;
745 
746                 case -EAGAIN:
747                     return;
748 
749                 default:
750                     alsa_logerr (written, "Failed to write %d frames from %p\n",
751                                  len, src);
752                     return;
753                 }
754             }
755 
756             alsa->wpos = (alsa->wpos + written) % hw->samples;
757             alsa->pending -= written;
758             len -= written;
759         }
760     }
761 }
762 
763 static int alsa_run_out (HWVoiceOut *hw, int live)
764 {
765     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
766     int decr;
767     snd_pcm_sframes_t avail;
768 
769     avail = alsa_get_avail (alsa->handle);
770     if (avail < 0) {
771         dolog ("Could not get number of available playback frames\n");
772         return 0;
773     }
774 
775     decr = audio_MIN (live, avail);
776     decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
777     alsa->pending += decr;
778     alsa_write_pending (alsa);
779     return decr;
780 }
781 
782 static void alsa_fini_out (HWVoiceOut *hw)
783 {
784     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
785 
786     ldebug ("alsa_fini\n");
787     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
788 
789     g_free(alsa->pcm_buf);
790     alsa->pcm_buf = NULL;
791 }
792 
793 static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
794                          void *drv_opaque)
795 {
796     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
797     struct alsa_params_req req;
798     struct alsa_params_obt obt;
799     snd_pcm_t *handle;
800     struct audsettings obt_as;
801     ALSAConf *conf = drv_opaque;
802 
803     req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
804     req.freq = as->freq;
805     req.nchannels = as->nchannels;
806     req.period_size = conf->period_size_out;
807     req.buffer_size = conf->buffer_size_out;
808     req.size_in_usec = conf->size_in_usec_out;
809     req.override_mask =
810         (conf->period_size_out_overridden ? 1 : 0) |
811         (conf->buffer_size_out_overridden ? 2 : 0);
812 
813     if (alsa_open (0, &req, &obt, &handle, conf)) {
814         return -1;
815     }
816 
817     obt_as.freq = obt.freq;
818     obt_as.nchannels = obt.nchannels;
819     obt_as.fmt = obt.fmt;
820     obt_as.endianness = obt.endianness;
821 
822     audio_pcm_init_info (&hw->info, &obt_as);
823     hw->samples = obt.samples;
824 
825     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
826     if (!alsa->pcm_buf) {
827         dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
828                hw->samples, 1 << hw->info.shift);
829         alsa_anal_close1 (&handle);
830         return -1;
831     }
832 
833     alsa->handle = handle;
834     alsa->pollhlp.conf = conf;
835     return 0;
836 }
837 
838 #define VOICE_CTL_PAUSE 0
839 #define VOICE_CTL_PREPARE 1
840 #define VOICE_CTL_START 2
841 
842 static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
843 {
844     int err;
845 
846     if (ctl == VOICE_CTL_PAUSE) {
847         err = snd_pcm_drop (handle);
848         if (err < 0) {
849             alsa_logerr (err, "Could not stop %s\n", typ);
850             return -1;
851         }
852     }
853     else {
854         err = snd_pcm_prepare (handle);
855         if (err < 0) {
856             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
857             return -1;
858         }
859         if (ctl == VOICE_CTL_START) {
860             err = snd_pcm_start(handle);
861             if (err < 0) {
862                 alsa_logerr (err, "Could not start handle for %s\n", typ);
863                 return -1;
864             }
865         }
866     }
867 
868     return 0;
869 }
870 
871 static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
872 {
873     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
874 
875     switch (cmd) {
876     case VOICE_ENABLE:
877         {
878             va_list ap;
879             int poll_mode;
880 
881             va_start (ap, cmd);
882             poll_mode = va_arg (ap, int);
883             va_end (ap);
884 
885             ldebug ("enabling voice\n");
886             if (poll_mode && alsa_poll_out (hw)) {
887                 poll_mode = 0;
888             }
889             hw->poll_mode = poll_mode;
890             return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
891         }
892 
893     case VOICE_DISABLE:
894         ldebug ("disabling voice\n");
895         if (hw->poll_mode) {
896             hw->poll_mode = 0;
897             alsa_fini_poll (&alsa->pollhlp);
898         }
899         return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
900     }
901 
902     return -1;
903 }
904 
905 static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
906 {
907     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
908     struct alsa_params_req req;
909     struct alsa_params_obt obt;
910     snd_pcm_t *handle;
911     struct audsettings obt_as;
912     ALSAConf *conf = drv_opaque;
913 
914     req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
915     req.freq = as->freq;
916     req.nchannels = as->nchannels;
917     req.period_size = conf->period_size_in;
918     req.buffer_size = conf->buffer_size_in;
919     req.size_in_usec = conf->size_in_usec_in;
920     req.override_mask =
921         (conf->period_size_in_overridden ? 1 : 0) |
922         (conf->buffer_size_in_overridden ? 2 : 0);
923 
924     if (alsa_open (1, &req, &obt, &handle, conf)) {
925         return -1;
926     }
927 
928     obt_as.freq = obt.freq;
929     obt_as.nchannels = obt.nchannels;
930     obt_as.fmt = obt.fmt;
931     obt_as.endianness = obt.endianness;
932 
933     audio_pcm_init_info (&hw->info, &obt_as);
934     hw->samples = obt.samples;
935 
936     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
937     if (!alsa->pcm_buf) {
938         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
939                hw->samples, 1 << hw->info.shift);
940         alsa_anal_close1 (&handle);
941         return -1;
942     }
943 
944     alsa->handle = handle;
945     alsa->pollhlp.conf = conf;
946     return 0;
947 }
948 
949 static void alsa_fini_in (HWVoiceIn *hw)
950 {
951     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
952 
953     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
954 
955     g_free(alsa->pcm_buf);
956     alsa->pcm_buf = NULL;
957 }
958 
959 static int alsa_run_in (HWVoiceIn *hw)
960 {
961     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
962     int hwshift = hw->info.shift;
963     int i;
964     int live = audio_pcm_hw_get_live_in (hw);
965     int dead = hw->samples - live;
966     int decr;
967     struct {
968         int add;
969         int len;
970     } bufs[2] = {
971         { .add = hw->wpos, .len = 0 },
972         { .add = 0,        .len = 0 }
973     };
974     snd_pcm_sframes_t avail;
975     snd_pcm_uframes_t read_samples = 0;
976 
977     if (!dead) {
978         return 0;
979     }
980 
981     avail = alsa_get_avail (alsa->handle);
982     if (avail < 0) {
983         dolog ("Could not get number of captured frames\n");
984         return 0;
985     }
986 
987     if (!avail) {
988         snd_pcm_state_t state;
989 
990         state = snd_pcm_state (alsa->handle);
991         switch (state) {
992         case SND_PCM_STATE_PREPARED:
993             avail = hw->samples;
994             break;
995         case SND_PCM_STATE_SUSPENDED:
996             /* stream is suspended and waiting for an application recovery */
997             if (alsa_resume (alsa->handle)) {
998                 dolog ("Failed to resume suspended input stream\n");
999                 return 0;
1000             }
1001             trace_alsa_resume_in();
1002             break;
1003         default:
1004             trace_alsa_no_frames(state);
1005             return 0;
1006         }
1007     }
1008 
1009     decr = audio_MIN (dead, avail);
1010     if (!decr) {
1011         return 0;
1012     }
1013 
1014     if (hw->wpos + decr > hw->samples) {
1015         bufs[0].len = (hw->samples - hw->wpos);
1016         bufs[1].len = (decr - (hw->samples - hw->wpos));
1017     }
1018     else {
1019         bufs[0].len = decr;
1020     }
1021 
1022     for (i = 0; i < 2; ++i) {
1023         void *src;
1024         struct st_sample *dst;
1025         snd_pcm_sframes_t nread;
1026         snd_pcm_uframes_t len;
1027 
1028         len = bufs[i].len;
1029 
1030         src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
1031         dst = hw->conv_buf + bufs[i].add;
1032 
1033         while (len) {
1034             nread = snd_pcm_readi (alsa->handle, src, len);
1035 
1036             if (nread <= 0) {
1037                 switch (nread) {
1038                 case 0:
1039                     trace_alsa_read_zero(len);
1040                     goto exit;
1041 
1042                 case -EPIPE:
1043                     if (alsa_recover (alsa->handle)) {
1044                         alsa_logerr (nread, "Failed to read %ld frames\n", len);
1045                         goto exit;
1046                     }
1047                     trace_alsa_xrun_in();
1048                     continue;
1049 
1050                 case -EAGAIN:
1051                     goto exit;
1052 
1053                 default:
1054                     alsa_logerr (
1055                         nread,
1056                         "Failed to read %ld frames from %p\n",
1057                         len,
1058                         src
1059                         );
1060                     goto exit;
1061                 }
1062             }
1063 
1064             hw->conv (dst, src, nread);
1065 
1066             src = advance (src, nread << hwshift);
1067             dst += nread;
1068 
1069             read_samples += nread;
1070             len -= nread;
1071         }
1072     }
1073 
1074  exit:
1075     hw->wpos = (hw->wpos + read_samples) % hw->samples;
1076     return read_samples;
1077 }
1078 
1079 static int alsa_read (SWVoiceIn *sw, void *buf, int size)
1080 {
1081     return audio_pcm_sw_read (sw, buf, size);
1082 }
1083 
1084 static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
1085 {
1086     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1087 
1088     switch (cmd) {
1089     case VOICE_ENABLE:
1090         {
1091             va_list ap;
1092             int poll_mode;
1093 
1094             va_start (ap, cmd);
1095             poll_mode = va_arg (ap, int);
1096             va_end (ap);
1097 
1098             ldebug ("enabling voice\n");
1099             if (poll_mode && alsa_poll_in (hw)) {
1100                 poll_mode = 0;
1101             }
1102             hw->poll_mode = poll_mode;
1103 
1104             return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
1105         }
1106 
1107     case VOICE_DISABLE:
1108         ldebug ("disabling voice\n");
1109         if (hw->poll_mode) {
1110             hw->poll_mode = 0;
1111             alsa_fini_poll (&alsa->pollhlp);
1112         }
1113         return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
1114     }
1115 
1116     return -1;
1117 }
1118 
1119 static ALSAConf glob_conf = {
1120     .buffer_size_out = 4096,
1121     .period_size_out = 1024,
1122     .pcm_name_out = "default",
1123     .pcm_name_in = "default",
1124 };
1125 
1126 static void *alsa_audio_init (void)
1127 {
1128     ALSAConf *conf = g_malloc(sizeof(ALSAConf));
1129     *conf = glob_conf;
1130     return conf;
1131 }
1132 
1133 static void alsa_audio_fini (void *opaque)
1134 {
1135     g_free(opaque);
1136 }
1137 
1138 static struct audio_option alsa_options[] = {
1139     {
1140         .name        = "DAC_SIZE_IN_USEC",
1141         .tag         = AUD_OPT_BOOL,
1142         .valp        = &glob_conf.size_in_usec_out,
1143         .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
1144     },
1145     {
1146         .name        = "DAC_PERIOD_SIZE",
1147         .tag         = AUD_OPT_INT,
1148         .valp        = &glob_conf.period_size_out,
1149         .descr       = "DAC period size (0 to go with system default)",
1150         .overriddenp = &glob_conf.period_size_out_overridden
1151     },
1152     {
1153         .name        = "DAC_BUFFER_SIZE",
1154         .tag         = AUD_OPT_INT,
1155         .valp        = &glob_conf.buffer_size_out,
1156         .descr       = "DAC buffer size (0 to go with system default)",
1157         .overriddenp = &glob_conf.buffer_size_out_overridden
1158     },
1159     {
1160         .name        = "ADC_SIZE_IN_USEC",
1161         .tag         = AUD_OPT_BOOL,
1162         .valp        = &glob_conf.size_in_usec_in,
1163         .descr       =
1164         "ADC period/buffer size in microseconds (otherwise in frames)"
1165     },
1166     {
1167         .name        = "ADC_PERIOD_SIZE",
1168         .tag         = AUD_OPT_INT,
1169         .valp        = &glob_conf.period_size_in,
1170         .descr       = "ADC period size (0 to go with system default)",
1171         .overriddenp = &glob_conf.period_size_in_overridden
1172     },
1173     {
1174         .name        = "ADC_BUFFER_SIZE",
1175         .tag         = AUD_OPT_INT,
1176         .valp        = &glob_conf.buffer_size_in,
1177         .descr       = "ADC buffer size (0 to go with system default)",
1178         .overriddenp = &glob_conf.buffer_size_in_overridden
1179     },
1180     {
1181         .name        = "THRESHOLD",
1182         .tag         = AUD_OPT_INT,
1183         .valp        = &glob_conf.threshold,
1184         .descr       = "(undocumented)"
1185     },
1186     {
1187         .name        = "DAC_DEV",
1188         .tag         = AUD_OPT_STR,
1189         .valp        = &glob_conf.pcm_name_out,
1190         .descr       = "DAC device name (for instance dmix)"
1191     },
1192     {
1193         .name        = "ADC_DEV",
1194         .tag         = AUD_OPT_STR,
1195         .valp        = &glob_conf.pcm_name_in,
1196         .descr       = "ADC device name"
1197     },
1198     { /* End of list */ }
1199 };
1200 
1201 static struct audio_pcm_ops alsa_pcm_ops = {
1202     .init_out = alsa_init_out,
1203     .fini_out = alsa_fini_out,
1204     .run_out  = alsa_run_out,
1205     .write    = alsa_write,
1206     .ctl_out  = alsa_ctl_out,
1207 
1208     .init_in  = alsa_init_in,
1209     .fini_in  = alsa_fini_in,
1210     .run_in   = alsa_run_in,
1211     .read     = alsa_read,
1212     .ctl_in   = alsa_ctl_in,
1213 };
1214 
1215 struct audio_driver alsa_audio_driver = {
1216     .name           = "alsa",
1217     .descr          = "ALSA http://www.alsa-project.org",
1218     .options        = alsa_options,
1219     .init           = alsa_audio_init,
1220     .fini           = alsa_audio_fini,
1221     .pcm_ops        = &alsa_pcm_ops,
1222     .can_be_default = 1,
1223     .max_voices_out = INT_MAX,
1224     .max_voices_in  = INT_MAX,
1225     .voice_size_out = sizeof (ALSAVoiceOut),
1226     .voice_size_in  = sizeof (ALSAVoiceIn)
1227 };
1228