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